function EEM_Ratio_Analyzer_GUI_CN()
% 定义全局变量用于存储 K_scatter 数据
global globalKScatterData;
globalKScatterData = [];

% 创建主窗口
fig = figure('Name', '3D-EEM Ratio Analyzer', ...
    'NumberTitle', 'off', ...
    'Position', [100, 100, 1200, 800], ...
    'Resize', 'on', ...
    'MenuBar', 'none', ...
    'ToolBar', 'none');

% 创建应用程序数据结构 - 先创建空结构
appData = struct();
appData.fig = fig;
appData.dataLoaded = false;
appData.calculationDone = false;

% 创建选项卡
tabgroup = uitabgroup('Parent', fig, 'Position', [0.02, 0.12, 0.96, 0.85]);

% 数据管理选项卡
dataTab = uitab('Parent', tabgroup, 'Title', 'Data Management');
% 计算选项卡
calcTab = uitab('Parent', tabgroup, 'Title', 'Calculation');
% 可视化选项卡
visTab = uitab('Parent', tabgroup, 'Title', 'Visualization');
% 结果选项卡
resultTab = uitab('Parent', tabgroup, 'Title', 'Results');

% 创建控制按钮
appData.ResetButton = uicontrol('Style', 'pushbutton', 'String', 'Reset', ...
    'Position', [50, 30, 80, 30], ...
    'Callback', @resetGUI);

appData.CloseButton = uicontrol('Style', 'pushbutton', 'String', 'Close', ...
    'Position', [150, 30, 80, 30], ...
    'Callback', @closeGUI);

appData.SaveDataButton = uicontrol('Style', 'pushbutton', 'String', 'Save Data', ...    
    'Position', [250, 30, 80, 30], ...
    'BackgroundColor', [0.2, 0.8, 0.2], ...  % 绿色背景
    'ForegroundColor', [1, 1, 1], ...        % 白色文字
    'FontWeight', 'bold', ...                % 粗体文字    
    'Callback', @saveAppDataCallback);

% 初始化所有选项卡，直接修改appData
appData = initDataTab(dataTab, appData);
appData = initCalcTab(calcTab, appData);
appData = initVisTab(visTab, appData);
appData = initResultTab(resultTab, appData);

% 保存应用程序数据到图形对象
setappdata(fig, 'appData', appData);

% 数据管理选项卡初始化
    function appData = initDataTab(parent, appData)
        panel = uipanel('Parent', parent, 'Title', 'Data Import', ...
            'Units', 'normalized', 'Position', [0.02, 0.02, 0.96, 0.96]);
        
        % EEM数据导入
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'EEM Data File (.mat):', ...
            'Units', 'normalized', 'Position', [0.05, 0.85, 0.15, 0.05], ...
            'HorizontalAlignment', 'left');
        
        appData.eemPathEdit = uicontrol('Parent', panel, 'Style', 'edit', ...
            'String', 'EEM_parafac_results_data.mat', ...
            'Units', 'normalized', 'Position', [0.05, 0.8, 0.6, 0.05]);
        
        appData.loadEEMBtn = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', 'Browse EEM', ...
            'Units', 'normalized', 'Position', [0.67, 0.8, 0.1, 0.05], ...
            'Callback', @browseEEMCallback);
        
        % 指标数据导入
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Indicator Data File (.xlsx):', ...
            'Units', 'normalized', 'Position', [0.05, 0.7, 0.15, 0.05], ...
            'HorizontalAlignment', 'left');
        
        appData.indicatorPathEdit = uicontrol('Parent', panel, 'Style', 'edit', ...
            'String', 'Indicator_data.xlsx', ...
            'Units', 'normalized', 'Position', [0.05, 0.65, 0.6, 0.05]);
        
        appData.loadIndicatorBtn = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', 'Browse Indicator', ...
            'Units', 'normalized', 'Position', [0.67, 0.65, 0.1, 0.05], ...
            'Callback', @browseIndicatorCallback);
        
        % 加载数据按钮
        appData.loadDataBtn = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', 'Load All Data', ...
            'Units', 'normalized', 'Position', [0.05, 0.55, 0.15, 0.06], ...
            'Callback', @loadDataCallback);
        
        %加载结果数据按钮
        appData.loadAppDataBtn = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', 'Load App Data', ...
            'Units', 'normalized', 'Position', [0.39, 0.55, 0.15, 0.06], ...
            'Callback', @loadAppDataCallback);       

        
        % 状态指示灯
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Status:', ...
            'Units', 'normalized', 'Position', [0.25, 0.56, 0.05, 0.05]);
        appData.dataStatusLamp = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', '', ...
            'Units', 'normalized', 'Position', [0.31, 0.56, 0.02, 0.05], ...
            'BackgroundColor', [0.5, 0.5, 0.5]);
        
        % 数据信息文本框
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Data Information:', ...
            'Units', 'normalized', 'Position', [0.05, 0.45, 0.15, 0.05], ...
            'HorizontalAlignment', 'left');
        
        appData.dataInfoText = uicontrol('Parent', panel, 'Style', 'listbox', ...
            'String', {'Click "Load All Data" to begin...'}, ...
            'Units', 'normalized', 'Position', [0.05, 0.05, 0.9, 0.4], ...
            'Max', 10, ...
            'Min', 0);
    end     
        
% 计算选项卡初始化
    function appData = initCalcTab(parent, appData)
         % 使用相对位置布局
        panel = uipanel('Parent', parent, 'Title', 'Calculation Settings', ...
            'Units', 'normalized', 'Position', [0.02, 0.02, 0.96, 0.96]);
        
        % P值设置
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'P-value threshold:', ...
            'Units', 'normalized', 'Position', [0.05, 0.85, 0.15, 0.05]);
        appData.pValueEdit = uicontrol('Parent', panel, 'Style', 'edit', ...
            'String', '0.01', ...
            'Units', 'normalized', 'Position', [0.21, 0.85, 0.1, 0.05]);
        
        % R值设置
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'R-value threshold:', ...
            'Units', 'normalized', 'Position', [0.35, 0.85, 0.15, 0.05]);
        appData.rValueEdit = uicontrol('Parent', panel, 'Style', 'edit', ...
            'String', '0.6', ...
            'Units', 'normalized', 'Position', [0.51, 0.85, 0.1, 0.05]);
        
        % 计算方法选择
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Correlation Method:', ...
            'Units', 'normalized', 'Position', [0.65, 0.85, 0.15, 0.05]);
        appData.correlationMethodPopup = uicontrol('Parent', panel, 'Style', 'popupmenu', ...
            'String', {'Pearson', 'Spearman'}, ...
            'Value', 1, ...
            'Units', 'normalized', 'Position', [0.81, 0.85, 0.14, 0.05]);
        
        % 开始计算按钮
        appData.calcBtn = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', 'Start Calculation', ...
            'Units', 'normalized', 'Position', [0.05, 0.75, 0.15, 0.06], ...
            'Callback', @startCalculationCallback);
        
        % 进度指示
        appData.progressLamp = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', '', ...
            'Units', 'normalized', 'Position', [0.22, 0.76, 0.02, 0.05], ...
            'BackgroundColor', [0.5, 0.5, 0.5]);
        
        appData.progressText = uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Ready for calculation', ...
            'Units', 'normalized', 'Position', [0.26, 0.75, 0.4, 0.06], ...
            'HorizontalAlignment', 'left');
        
        % 计算信息显示
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Calculation Information:', ...
            'Units', 'normalized', 'Position', [0.05, 0.65, 0.2, 0.05]);
        
        appData.calcInfoText = uicontrol('Parent', panel, 'Style', 'listbox', ...
            'String', {'No calculation performed yet.'}, ...
            'Units', 'normalized', 'Position', [0.05, 0.05, 0.9, 0.6]);

    end

% 可视化选项卡初始化
    function appData = initVisTab(parent, appData)
        % 绘图控制面板
        controlPanel = uipanel('Parent', parent, 'Title', 'Plot Controls', ...
            'Units', 'normalized', 'Position', [0.02, 0.85, 0.96, 0.13]);
        
        % 绘图类型选择
        uicontrol('Parent', controlPanel, 'Style', 'text', ...
            'String', 'Plot Type:', ...
            'Units', 'normalized', 'Position', [0.02, 0.4, 0.08, 0.4]);
        appData.plotTypePopup = uicontrol('Parent', controlPanel, 'Style', 'popupmenu', ...
            'String', {'All','PPP Contour', 'Correlation Map', 'Best Ratio Fit',...
            'Region Analysis'}, ...
            'Units', 'normalized', 'Position', [0.11, 0.4, 0.15, 0.4]);
        
        % 指标选择（可视化）
        uicontrol('Parent', controlPanel, 'Style', 'text', ...
            'String', 'Indicator:', ...
            'Units', 'normalized', 'Position', [0.27, 0.4, 0.08, 0.4]);
        appData.visIndicatorPopup = uicontrol('Parent', controlPanel, 'Style', 'popupmenu', ...
            'String', {'Select indicator...'}, ...
            'Units', 'normalized', 'Position', [0.36, 0.4, 0.17, 0.4]);
        
        % DF参数设置 
        uicontrol('Parent', controlPanel, 'Style', 'text', ...
            'String', 'DF threshold:', ...
            'Units', 'normalized', 'Position', [0.55, 0.4, 0.08, 0.4]);
        appData.dfValueEdit = uicontrol('Parent', controlPanel, 'Style', 'edit', ...
            'String', '0.5', ...
            'Units', 'normalized', 'Position', [0.65, 0.4, 0.05, 0.4]);        
        
        % 更新绘图按钮
        appData.updatePlotBtn = uicontrol('Parent', controlPanel, 'Style', 'pushbutton', ...
            'String', 'Update Plot', ...
            'Units', 'normalized', 'Position', [0.75, 0.4, 0.1, 0.4], ...
            'Callback', @updatePlotCallback);
        
        % 导出拟合数据按钮 
        appData.exportFitDataBtn = uicontrol('Parent', controlPanel, 'Style', 'pushbutton', ...
            'String', 'Export Fit Data', ...
            'Units', 'normalized', 'Position', [0.89, 0.4, 0.1, 0.4], ...
            'Callback', @exportFitDataCallback);
        
        
        % 创建六个坐标轴用于绘图 - 使用相对位置
        % 第一行
        appData.axes1 = axes('Parent', parent, 'Units', 'normalized', ...
            'Position', [0.05, 0.50, 0.25, 0.25]);
        title(appData.axes1, 'PPP Distribution');
        xlabel('Em (nm)');
        ylabel('Ex (nm)');      
        
        appData.axes2 = axes('Parent', parent, 'Units', 'normalized', ...
            'Position', [0.36, 0.50, 0.25, 0.25]);
        title(appData.axes2, 'Correlation Map');
        xlabel('Em (nm)');
        ylabel('Ex (nm)');
        
        appData.axes4 = axes('Parent', parent, 'Units', 'normalized', ...
            'Position', [0.67, 0.50, 0.25, 0.25]);
        title(appData.axes4, 'Best Ratio Fit');
        
        % 第二行
        appData.axes3 = axes('Parent', parent, 'Units', 'normalized', ...
            'Position', [0.05, 0.10, 0.25, 0.25]);
        title(appData.axes3, 'PPP Distribution (Region)');
        xlabel('Em (nm)');
        ylabel('Ex (nm)');
        
        appData.axes5 = axes('Parent', parent, 'Units', 'normalized', ...
            'Position', [0.36, 0.10, 0.25, 0.25]);
        title(appData.axes5, 'Correlation Map (Region)');
        xlabel('Em (nm)');
        ylabel('Ex (nm)');
        
        appData.axes6 = axes('Parent', parent, 'Units', 'normalized', ...
            'Position', [0.67, 0.10, 0.25, 0.25]);
        title(appData.axes6, 'Best Ratio Fit (Region)');
        
        % 初始化选择存储 
        appData.currentSelection = struct('Ex1', [], 'Em1', [], 'Ex2', [], 'Em2', [], ...
            'idxEx1', [], 'idxEm1', [], 'idxEx2', [], 'idxEm2', []);
        appData.currentFitData = [];  
   
        % 区域选择相关变量初始化
        appData.regionSelection = struct(...
            'selectedPoints', [], ...           % PPP选中的点
            'rect', [], ...                     % PPP区域选择矩形
            'timerObj', [], ...                 % PPP区域定时器
            'startX', [], ...                   % PPP区域起始X
            'startY', [], ...                   % PPP区域起始Y
            'K_selectedPoints', [], ...         % K矩阵选中的点
            'K_rect', [], ...                   % K矩阵区域选择矩形
            'K_timerObj', [], ...               % K矩阵区域定时器
            'K_startX', [], ...                 % K矩阵区域起始X
            'K_startY', [] ...                  % K矩阵区域起始Y
        );
        
        appData.regionData = struct(...
            'PPP_2D',struct('em', [], 'ex', [], 'ppp', [], 'size', [], 'range', []), ...                   % PPP二维散点数据
            'K_matrix', [], ...                 % K矩阵数据
            'K_scatter', [] ...                 % K矩阵散点数据
        );
        
        % 【新增】初始化K_scatter结构
        appData.regionData.K_scatter = struct(...
            'em', [], ...                       % 发射波长
            'ex', [], ...                       % 激发波长
            'k', [], ...                        % K值
            'size', [], ...                     % 散点大小
            'range', [] ...                     % K值范围
        );
        
        % 【新增】初始化K_selectedPoints结构
        appData.regionSelection.K_selectedPoints = struct(...
            'em', [], ...                       % 选中的发射波长
            'ex', [], ...                       % 选中的激发波长
            'k', [] ...                         % 选中的K值
        );
        
        % 【新增】初始化selectedPoints结构
        appData.regionSelection.selectedPoints = struct(...
            'em', [], ...                       % 选中的发射波长
            'ex', [], ...                       % 选中的激发波长
            'ppp', [] ...                       % 选中的PPP值
        );
        
    end

% 结果选项卡初始化
    function appData = initResultTab(parent, appData)
        % 使用相对位置布局
        panel = uipanel('Parent', parent, 'Title', 'Results', ...
            'Units', 'normalized', 'Position', [0.02, 0.02, 0.96, 0.96]);
        
        % 结果表格
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Significant Wavelength Pairs:', ...
            'Units', 'normalized', 'Position', [0.05, 0.9, 0.25, 0.04]);
        
        appData.resultsTable = uitable('Parent', panel, ...
            'Units', 'normalized', 'Position', [0.05, 0.55, 0.6, 0.35], ...
            'ColumnName', {'Ex_num', 'Em_num', 'Ex_den', 'Em_den', 'R_value', 'P_value'});
        
        % 导出结果按钮
        appData.exportBtn = uicontrol('Parent', panel, 'Style', 'pushbutton', ...
            'String', 'Export Results to Excel', ...
            'Units', 'normalized', 'Position', [0.05, 0.5, 0.15, 0.04], ...
            'Callback', @exportResultsCallback);
        
        % 最佳比值信息
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Best Ratio Information:', ...
            'Units', 'normalized', 'Position', [0.67, 0.9, 0.25, 0.04]);
        
        appData.bestRatioText = uicontrol('Parent', panel, 'Style', 'listbox', ...
            'String', {'Results will appear here after calculation.'}, ...
            'Units', 'normalized', 'Position', [0.67, 0.55, 0.28, 0.35]);
        
        % 详细结果显示
        uicontrol('Parent', panel, 'Style', 'text', ...
            'String', 'Detailed Results:', ...
            'Units', 'normalized', 'Position', [0.05, 0.45, 0.15, 0.04]);
        
        appData.detailedResultsText = uicontrol('Parent', panel, 'Style', 'listbox', ...
            'String', {'No detailed results available.'}, ...
            'Units', 'normalized', 'Position', [0.05, 0.05, 0.9, 0.4]);
    end


% 回调函数
    function browseEEMCallback(~, ~)
        appData = getappdata(fig, 'appData');
        [filename, pathname] = uigetfile('*.mat', 'Select EEM Data File');
        if filename ~= 0
            fullpath = fullfile(pathname, filename);
            set(appData.eemPathEdit, 'String', fullpath);
            setappdata(fig, 'appData', appData);
        end
    end

    function browseIndicatorCallback(~, ~)
        appData = getappdata(fig, 'appData');
        [filename, pathname] = uigetfile('*.xlsx', 'Select Indicator Data File');
        if filename ~= 0
            fullpath = fullfile(pathname, filename);
            set(appData.indicatorPathEdit, 'String', fullpath);
            setappdata(fig, 'appData', appData);
        end
    end

    function loadDataCallback(~, ~)
        appData = getappdata(fig, 'appData');
        
        try
            % 更新状态
            set(appData.dataStatusLamp, 'BackgroundColor', 'yellow');
            set(appData.dataInfoText, 'String', {'Loading data...'},'Value',1);
            drawnow;
            
            % 获取文件路径
            eemFile = get(appData.eemPathEdit, 'String');
            indicatorFile = get(appData.indicatorPathEdit, 'String');
            
            % 加载PARAFAC结果
            if exist(eemFile, 'file')
                temp = load(eemFile);
                appData.Results = temp.Results;
                infoStr = get(appData.dataInfoText, 'String');
                infoStr{end+1} = sprintf('EEM data loaded: %s', eemFile);
                set(appData.dataInfoText, 'String', infoStr);
            else
                error('EEM data file not found: %s', eemFile);
            end
            
            % 加载Excel数据
            if exist(indicatorFile, 'file')
                [num, txt, raw] = xlsread(indicatorFile);
                appData.raw = raw;
                appData.IF_r = num;
                infoStr = get(appData.dataInfoText, 'String');
                infoStr{end+1} = sprintf('Indicator data loaded: %s', indicatorFile);
                set(appData.dataInfoText, 'String', infoStr);
            else
                error('Indicator data file not found: %s', indicatorFile);
            end
            
            % 提取基本信息
            appData.EEM_dataname = appData.Results.EEM.Data_name;
            appData.IF_dataname = appData.raw(2:end,1);
            appData.Ex = appData.Results.EEM.Ex;
            appData.Em = appData.Results.EEM.Em;
            appData.nEx = appData.Results.EEM.nEx;
            appData.nEm = appData.Results.EEM.nEm;
            
            % 找到共同项目
            commonItems = intersect(appData.EEM_dataname, appData.IF_dataname);
            [~, idx1] = ismember(commonItems, appData.EEM_dataname);
            [~, idx2] = ismember(commonItems, appData.IF_dataname);
            
            % 提取IF数据
            appData.IF_r = appData.IF_r(idx2,:);
            
            % 更新指标选择下拉菜单
            if size(appData.raw, 2) > 1
                indicatorNames = appData.raw(1,2:end);
                set(appData.visIndicatorPopup, 'String', indicatorNames);
                infoStr = get(appData.dataInfoText, 'String');
                infoStr{end+1} = sprintf('Available indicators: %d', length(indicatorNames));
                set(appData.dataInfoText, 'String', infoStr,'Value',1);
            end
            
            % 更新UI
            set(appData.dataStatusLamp, 'BackgroundColor', 'green');
            infoStr = get(appData.dataInfoText, 'String');
            infoStr{end+1} = '----------------------------------------';
            infoStr{end+1} = sprintf('EEM Data: %d samples', length(appData.EEM_dataname));
            infoStr{end+1} = sprintf('Indicators: %d parameters', size(appData.IF_r,2));
            infoStr{end+1} = sprintf('Excitation: %d wavelengths (%.0f-%.0f nm)', ...
                appData.nEx, min(appData.Ex), max(appData.Ex));
            infoStr{end+1} = sprintf('Emission: %d wavelengths (%.0f-%.0f nm)', ...
                appData.nEm, min(appData.Em), max(appData.Em));
            infoStr{end+1} = sprintf('Common samples: %d', length(commonItems));
            infoStr{end+1} = 'Data loading completed successfully!';
            set(appData.dataInfoText, 'String', infoStr,'Value',1);
            
            appData.dataLoaded = true;
            setappdata(fig, 'appData', appData);
            
        catch ME
            set(appData.dataStatusLamp, 'BackgroundColor', 'red');
            errorStr = {'Error loading data:', ME.message};
            set(appData.dataInfoText, 'String', errorStr,'Value',1);
            setappdata(fig, 'appData', appData);
        end
    end

 % 回调函数
    function startCalculationCallback(~, ~)
        appData = getappdata(fig, 'appData');
        
        if ~appData.dataLoaded
            msgbox('Please load data first!', 'Warning', 'warn');
            return;
        end
        
        try
            % 更新进度
            set(appData.progressLamp, 'BackgroundColor', 'yellow');
            set(appData.progressText, 'String', 'Calculating EEM ratios...');
            set(appData.calcInfoText, 'String', {'Starting calculation...'}, 'Value', 1);
            drawnow;
            
            % 获取参数
            appData.pv = str2double(get(appData.pValueEdit, 'String'));
            appData.rv = str2double(get(appData.rValueEdit, 'String'));
            
            % 获取选择的计算方法
            methodList = get(appData.correlationMethodPopup, 'String');
            selectedMethod = methodList{get(appData.correlationMethodPopup, 'Value')};
            
            % 找到共同项目
            commonItems = intersect(appData.EEM_dataname, appData.IF_dataname);
            [~, idx1] = ismember(commonItems, appData.EEM_dataname);
            
            % 计算EEM比值
            X = appData.Results.EEM.X(idx1,:,:);
%             X_den = reshape(X, size(X,1), 1, 1, size(X,2), size(X,3));
%             EEM_R = X ./ X_den;
            EEM_R = X ./ reshape(X, size(X,1), 1, 1, size(X,2), size(X,3));
            
            
            % 初始化相关数组
            nIndicators = size(appData.IF_r,2);
            appData.r = zeros(nIndicators, appData.nEm, appData.nEx, appData.nEm, appData.nEx);
            appData.p = zeros(nIndicators, appData.nEm, appData.nEx, appData.nEm, appData.nEx);
            
            % 计算相关性
            infoStr = get(appData.calcInfoText, 'String');
            infoStr{end+1} = sprintf('Calculating correlations using %s method...', selectedMethod);
            set(appData.calcInfoText, 'String', infoStr, 'Value',1);
                                
            h = waitbar(0, sprintf('Calculating correlations with %s method...', selectedMethod));
            for ii = 1:nIndicators
                [appData.r(ii,:,:,:,:), appData.p(ii,:,:,:,:)] = ...
                    corr5D2_gpu(EEM_R, appData.IF_r, ii, appData.nEm, appData.nEx, selectedMethod);
                waitbar(ii/nIndicators, h, sprintf('Progress: %.1f%%', ii/nIndicators*100));
                
                % 更新进度信息
                if mod(ii, 5) == 0 || ii == nIndicators
                    infoStr = get(appData.calcInfoText, 'String');
                    infoStr{end+1} = sprintf('Completed %d/%d indicators', ii, nIndicators);
                    set(appData.calcInfoText, 'String', infoStr);
                    drawnow;
                end
            end
            close(h);
            
           
            % 计算PPP
            appData = calculatePPP(appData);
            
            % 找到显著比值
            appData = findSignificantRatios(appData);
            
            % 更新进度
            set(appData.progressLamp, 'BackgroundColor', 'green');
            set(appData.progressText, 'String', 'Calculation completed!');
            
            infoStr = get(appData.calcInfoText, 'String');
            infoStr{end+1} = '----------------------------------------';
            infoStr{end+1} = sprintf('Calculation completed successfully!');
            infoStr{end+1} = sprintf('Method used: %s', selectedMethod);
            infoStr{end+1} = sprintf('Found %d significant wavelength pairs', size(appData.Ind_output, 1));
            infoStr{end+1} = sprintf('P-value threshold: %.3f', appData.pv);
            infoStr{end+1} = sprintf('R-value threshold: %.3f', appData.rv);
            set(appData.calcInfoText, 'String', infoStr, 'Value', 1);
            
            appData.calculationDone = true;
            setappdata(fig, 'appData', appData);
            
            % 更新结果表格
            updateResultsTable(appData);
            
        catch ME
            set(appData.progressLamp, 'BackgroundColor', 'red');
            set(appData.progressText, 'String', sprintf('Calculation error: %s', ME.message));
            errorStr = get(appData.calcInfoText, 'String');
            errorStr{end+1} = '----------------------------------------';
            errorStr{end+1} = sprintf('ERROR: %s', ME.message);
            set(appData.calcInfoText, 'String', errorStr, 'Value', 1);
            setappdata(fig, 'appData', appData);
        end
    end

    function appData = calculatePPP(appData)
        % 计算PPP值
        k = 0;
        appData.exm = [];
        appData.PPP = zeros(size(appData.r,1), appData.nEm, appData.nEx);
        
        infoStr = get(appData.calcInfoText, 'String');
        infoStr{end+1} = 'Calculating PPP values...';
        set(appData.calcInfoText, 'String', infoStr, 'Value', 1);
        drawnow;
        
        for em = 1:appData.nEm    
            for ex = 1:appData.nEx
                if appData.Ex(ex) > 0.5 * appData.Em(em) && appData.Ex(ex) < appData.Em(em)
                    k = k + 1;
                    appData.exm(k,:) = [ex, em];
                    PP_pv = squeeze(appData.p(:,:,:,em,ex));
                    
                    for em1 = 1:appData.nEm    
                        for ex1 = 1:appData.nEx
                            if appData.Ex(ex1) <= 0.5 * appData.Em(em1) || appData.Ex(ex1) >= appData.Em(em1)
                               PP_pv(:,em1,ex1)= NaN;    
                            end                            
                        end
                    end                    
                    
                    PP_pv(PP_pv > appData.pv) = NaN;
                    PP_pv(PP_pv <= appData.pv) = 1;
                    appData.PPP(:,em,ex) = sum(sum(PP_pv, 3, 'omitnan'), 2, 'omitnan');
                end
            end
        end
        appData.PPP = appData.PPP / k;
        
        infoStr = get(appData.calcInfoText, 'String');
        infoStr{end+1} = sprintf('PPP calculation completed. Valid wavelength pairs: %d', k);
        set(appData.calcInfoText, 'String', infoStr, 'Value', 1);
    end

    function appData = findSignificantRatios(appData)
        % 找到所有指标的显著波长对
        appData.Ind_output = [];
        k = 0;
        
        infoStr = get(appData.calcInfoText, 'String');
        infoStr{end+1} = 'Finding significant wavelength pairs for all indicators...';
        set(appData.calcInfoText, 'String', infoStr, 'Value', 1);
        drawnow;       

        
        % 为每个指标查找显著波长对
        nIndicators = size(appData.IF_r, 2);
        totalPairs = 0;
        
        for ind = 1:nIndicators
            indicatorPairs = 0;
            k = 0;
            
            for em = 1:appData.nEm    
                for ex = 1:appData.nEx
                    if appData.Ex(ex) > 0.5 * appData.Em(em) && appData.Ex(ex) < appData.Em(em)

                        PP_pv = squeeze(appData.p(ind,:,:,em,ex));
                        RR_pv = squeeze(appData.r(ind,:,:,em,ex));    
                        [em_3, ex_3] = find(PP_pv < appData.pv & abs(RR_pv) > appData.rv);
                        RR_temp = RR_pv(PP_pv < appData.pv & abs(RR_pv) > appData.rv);
                        PP_temp = PP_pv(PP_pv < appData.pv & abs(RR_pv) > appData.rv);
                        
                        if ~isempty(em_3)
                            exm_deno = repmat([ex, em], length(em_3), 1);
                            new_entries = [appData.Ex(ex_3)', appData.Em(em_3)',...
                                appData.Ex(exm_deno(:,1))', appData.Em(exm_deno(:,2))',...
                                RR_temp, PP_temp, repmat(ind, length(em_3), 1)];
                            appData.Ind_output = [appData.Ind_output; new_entries];
                            indicatorPairs = indicatorPairs + length(em_3);
                        end
                    end
                end
            end
            
            totalPairs = totalPairs + indicatorPairs;
            
            % 更新进度信息
            if mod(ind, 1) == 0 || ind == nIndicators
                infoStr = get(appData.calcInfoText, 'String');
                infoStr{end+1} = sprintf('Indicator %d: found %d significant pairs', ind, indicatorPairs);
                set(appData.calcInfoText, 'String', infoStr);
                drawnow;
            end
        end

        infoStr = get(appData.calcInfoText, 'String');
        infoStr{end+1} = sprintf('Total significant pairs found for all indicators: %d', totalPairs);
        set(appData.calcInfoText, 'String', infoStr, 'Value', 1);

    end


    function updatePlotCallback(~, ~)
        appData = getappdata(fig, 'appData');
        appData.rv = str2double(get(appData.rValueEdit, 'String'));
        if ~appData.calculationDone
            msgbox('Please run calculation first!', 'Warning', 'warn');
            return;
        end
        
        % 更新指标选择
        appData.IND = get(appData.visIndicatorPopup, 'Value');
        setappdata(fig, 'appData', appData);
        
        plotType = get(appData.plotTypePopup, 'Value');
        
        switch plotType
            case 1 % All
                plotPPP(appData);
                plotCorrelationMap(appData);
                plotBestFit(appData);
                plotRegionPPP(appData); 

            case 2 % PPP Contour
                plotPPP(appData);                
            case 3 % Correlation Map
                plotCorrelationMap(appData);
            case 4 % Best Ratio Fit
                plotBestFit(appData);
            case 5 % Region Analysis 
                plotRegionPPP(appData);
                plotRegionCorrelation(appData);
                plotRegionBestFit(appData);
            
        end
                        

        
    end

    function plotPPP(appData)
        % 绘制PPP等值线图
        axes(appData.axes1);
        cla;
        if ~isempty(appData.PPP)
            contourf(appData.Em, appData.Ex, squeeze(appData.PPP(appData.IND,:,:))', ...
            'LineStyle', 'none', 'HitTest', 'off');
            colorbar;
            title(sprintf('%s - PPP Distribution', appData.raw{1, appData.IND+1}));
            xlabel('Em (nm)');
            ylabel('Ex (nm)');   
            % 设置点击回调 
            set(appData.axes1, 'ButtonDownFcn', @selectDenominator);  % 【新增】            
        end
    end

    function selectDenominator(~, event)
        appData = getappdata(fig, 'appData');
        
        if isempty(appData.Ex) || isempty(appData.Em)
            return;
        end
        
        % 获取点击位置
        currentPoint = get(appData.axes1, 'CurrentPoint');

        targetEx = currentPoint(1,2);  % 第一行的第一个元素是 x 坐标（Em）
        targetEm = currentPoint(1,1);  % 第一行的第二个元素是 y 坐标（Ex）
        
        % 找到最近的波长索引
        [~, idxEm] = min(abs(appData.Em - targetEm));
        [~, idxEx] = min(abs(appData.Ex - targetEx));
  
        % 存储分母选择
        appData.currentSelection.Em1 = appData.Em(idxEm);
        appData.currentSelection.Ex1 = appData.Ex(idxEx);
        appData.currentSelection.idxEm1 = idxEm;
        appData.currentSelection.idxEx1 = idxEx;
        
        setappdata(fig, 'appData', appData);
        
        % 更新相关图
        plotCorrelationMap(appData);
    end


    function plotCorrelationMap(appData)
        % 绘制相关图
        axes(appData.axes2);
        cla;
        
        if ~isempty(appData.currentSelection.idxEx1) && ~isempty(appData.currentSelection.idxEm1)
            ex_1 = appData.currentSelection.Ex1;
            em_1 = appData.currentSelection.Em1;
            ex_2 = appData.currentSelection.idxEx1;
            em_2 = appData.currentSelection.idxEm1;
            
            RR = squeeze(appData.r(appData.IND,:,:,em_2,ex_2));
            PP = squeeze(appData.p(appData.IND,:,:,em_2,ex_2));

            for em1 = 1:appData.nEm    
                for ex1 = 1:appData.nEx
                    if appData.Ex(ex1) <= 0.5 * appData.Em(em1) || appData.Ex(ex1) >= appData.Em(em1)
                       RR(em1,ex1)= NaN;    
                    end                            
                end
            end         
            
            RR_pv = RR;
            RR_pv(PP > appData.pv) = NaN;
            RR_pv(abs(RR_pv) < appData.rv) = NaN;
            
            contourf(appData.Em, appData.Ex, squeeze(RR_pv)', ...
            'LineStyle', 'none', 'HitTest', 'off');
            xlabel('Em (nm)'); 
            ylabel('Ex (nm)');
            colorbar;
            title(sprintf('%s (Ex%.0f|Em%.0f)',...
                appData.raw{1,appData.IND+1}, ex_1, em_1));
            
            % 设置点击回调
            set(appData.axes2, 'ButtonDownFcn', @selectNumerator);
        else
            % 如果没有选择分母，使用默认值
            if size(appData.Ind_output, 1) > 0
                ex_1 = appData.Ind_output(1,1);
                em_1 = appData.Ind_output(1,2);
            else
                ex_1 = 275;
                em_1 = 364;
            end
            
            ex_2 = find(appData.Ex == ex_1);
            em_2 = find(appData.Em == em_1);
            
            RR = squeeze(appData.r(appData.IND,:,:,em_2,ex_2));
            PP = squeeze(appData.p(appData.IND,:,:,em_2,ex_2));
            
            for em1 = 1:appData.nEm    
                for ex1 = 1:appData.nEx
                    if appData.Ex(ex1) <= 0.5 * appData.Em(em1) || appData.Ex(ex1) >= appData.Em(em1)
                       RR(em1,ex1)= NaN;    
                    end                            
                end
            end                     
                        
            RR_pv = RR;
            RR_pv(PP > appData.pv) = NaN;
            RR_pv(abs(RR_pv) < appData.rv) = NaN;
            
            contourf(appData.Em, appData.Ex, squeeze(RR_pv)', ...
            'LineStyle', 'none', 'HitTest', 'off');
            xlabel('Em (nm)'); 
            ylabel('Ex (nm)');        
            colorbar;
            title(sprintf('%s (Ex%.0f|Em%.0f)',...
                appData.raw{1,appData.IND+1}, ex_1, em_1));
            
            % 设置点击回调
            set(appData.axes2, 'ButtonDownFcn', @selectNumerator);
        end
    end

    function selectNumerator(~, event)
        appData = getappdata(fig, 'appData');
        
        if isempty(appData.Ex) || isempty(appData.Em) || ...
           isempty(appData.currentSelection.idxEx1) || isempty(appData.currentSelection.idxEm1)
            return;
        end
        
        % 获取点击位置
        pos = event.IntersectionPoint(1:2);
        targetEm = pos(1);
        targetEx = pos(2);
        
        
        % 找到最近的波长索引
        [~, idxEm] = min(abs(appData.Em - targetEm));
        [~, idxEx] = min(abs(appData.Ex - targetEx));
        
        % 存储分子选择
        appData.currentSelection.Em2 = appData.Em(idxEm);
        appData.currentSelection.Ex2 = appData.Ex(idxEx);
        appData.currentSelection.idxEm2 = idxEm;
        appData.currentSelection.idxEx2 = idxEx;
        
        setappdata(fig, 'appData', appData);
        
        % 更新最佳比值拟合图
        plotBestFit(appData);
    end

    function plotBestFit(appData)
        % 绘制最佳比值线性拟合
        axes(appData.axes4);
        cla;
        % 找到共同项目
        commonItems = intersect(appData.EEM_dataname, appData.IF_dataname);
        [~, idx1] = ismember(commonItems, appData.EEM_dataname);

        % 计算EEM比值
        X = appData.Results.EEM.X(idx1,:,:); 
        
        
        if ~isempty(appData.currentSelection.idxEx1) && ~isempty(appData.currentSelection.idxEm1) && ...
           ~isempty(appData.currentSelection.idxEx2) && ~isempty(appData.currentSelection.idxEm2)
            
            ex_num = appData.currentSelection.idxEx2;
            em_num = appData.currentSelection.idxEm2;
            ex_den = appData.currentSelection.idxEx1;
            em_den = appData.currentSelection.idxEm1;


            
            % 提取拟合数据
            X_vals = squeeze(X(:,em_num,ex_num)) ./ ...
                     squeeze(X(:,em_den,ex_den));
            y_vals = appData.IF_r(:,appData.IND);
            
            valid_idx = ~isnan(X_vals) & ~isnan(y_vals) & ~isinf(X_vals);
            X_vals = X_vals(valid_idx);
            y_vals = y_vals(valid_idx);
            
            if length(X_vals) > 1
                % 线性拟合
                [p, S] = polyfit(X_vals, y_vals, 1);
                y_fit = polyval(p, X_vals);
                
                % 绘图
                scatter(appData.axes4, X_vals, y_vals, 'bo');
                hold on;
                plot(appData.axes4, X_vals, y_fit, 'r-', 'LineWidth', 2);
                
                % 计算R?
                R2 = 1 - sum((y_vals - y_fit).^2) / sum((y_vals - mean(y_vals)).^2);
                                
                % 【新增】计算拟合统计信息
                n = length(X_vals);
                y_mean = mean(y_vals);
                SSR = sum((y_fit - y_mean).^2);  % 回归平方和
                SSE = sum((y_vals - y_fit).^2);  % 残差平方和
                SST = sum((y_vals - y_mean).^2); % 总平方和  
                
                % F统计量
                F_stat = (SSR / (2-1)) / (SSE / (n-2));

                % 回归模型的p值 (F检验)
                p_model = 1 - fcdf(F_stat, 1, n-2);                            
                

                % 计算标准误差
                se_slope = sqrt(SSE / (n-2)) / sqrt(sum((X_vals - mean(X_vals)).^2));
                se_intercept = sqrt(SSE / (n-2)) * sqrt(1/n + mean(X_vals)^2 / sum((X_vals - mean(X_vals)).^2));

                % 计算t统计量
                t_slope = p(1) / se_slope;
                t_intercept = p(2) / se_intercept;

                % 计算p值（双尾检验）
                p_slope = 2 * (1 - tcdf(abs(t_slope), n-2));
                p_intercept = 2 * (1 - tcdf(abs(t_intercept), n-2));

                indicatorNames = appData.raw(1,2:end);
                indicatorName = indicatorNames{appData.IND};                    

                % 【修改】标题包含模型显著性
                if p_model < 0.001
                    p_model_str = '< 0.001';
                else
                    p_model_str = sprintf('= %.4f', p_model);
                end

                title_str = sprintf('%s - Ratio Fit\nR^2 = %.4f, F-test p %s, n = %d', ...
                    indicatorName, R2, p_model_str, n);
                title(appData.axes4, title_str);
                
                xlabel(appData.axes4, sprintf('Ex%.0fEm%.0f/Ex%.0fEm%.0f',...
                    appData.currentSelection.Ex2, appData.currentSelection.Em2, ...
                    appData.currentSelection.Ex1, appData.currentSelection.Em1));
                ylabel(appData.axes4, indicatorName);
                
                % 【新增】在图上添加拟合方程和p值
                equation_str = sprintf('y = %.4f*x + %.4f', p(1), p(2));
                pvalue_str = sprintf('p(slope) = %.4f\np(intercept) = %.4f', p_slope, p_intercept);

                % 选择合适的位置显示文本（右上角）
                x_lim = xlim(appData.axes4);
                y_lim = ylim(appData.axes4);
                text_x = x_lim(1) + 0.05 * (x_lim(2) - x_lim(1));
                text_y = y_lim(2) - 0.15 * (y_lim(2) - y_lim(1));

                text(appData.axes4, text_x, text_y, equation_str, ...
                    'VerticalAlignment', 'top', 'FontSize', 6, ...
                    'BackgroundColor', 'none', 'EdgeColor', 'none');

                text_y2 = y_lim(2) - 0.25 * (y_lim(2) - y_lim(1));
                text(appData.axes4, text_x, text_y2, pvalue_str, ...
                    'VerticalAlignment', 'top', 'FontSize', 6, ...
                    'BackgroundColor', 'none', 'EdgeColor', 'none');

                legend(appData.axes4, 'Data', 'Linear Fit', 'Location', 'best');
                grid on;
                hold off;
                
                % 存储拟合数据
                appData.currentFitData.X_vals = X_vals;
                appData.currentFitData.y_vals = y_vals;
                appData.currentFitData.y_fit = y_fit;
                appData.currentFitData.R2 = R2;
                appData.currentFitData.p = p;
                appData.currentFitData.p_slope = p_slope;     
                appData.currentFitData.p_intercept = p_intercept;
                appData.currentFitData.n = n;             
                appData.currentFitData.equation_str = equation_str;   
                setappdata(fig, 'appData', appData);
            else
                title(appData.axes4, 'Not enough valid data for fitting');
            end
        else
            % 如果没有选择，使用最佳比值对
            if ~isempty(appData.Ind_output)
                currentIndicator = get(appData.visIndicatorPopup, 'Value');
                indicatorPairs = appData.Ind_output(appData.Ind_output(:,7) == currentIndicator, :);
                if ~isempty(indicatorPairs)
                    [~, bestIdx] = min(indicatorPairs(:,6));
                    bestPair = indicatorPairs(bestIdx,:);
                    
                    ex_num = find(appData.Ex == bestPair(1));
                    em_num = find(appData.Em == bestPair(2));
                    ex_den = find(appData.Ex == bestPair(3));
                    em_den = find(appData.Em == bestPair(4));
                    
                    % 提取拟合数据
                    X_vals = squeeze(X(:,em_num,ex_num)) ./ ...
                             squeeze(X(:,em_den,ex_den));
                    y_vals = appData.IF_r(:,currentIndicator);
                    
                    valid_idx = ~isnan(X_vals) & ~isnan(y_vals) & ~isinf(X_vals);
                    X_vals = X_vals(valid_idx);
                    y_vals = y_vals(valid_idx);
                    
                    if length(X_vals) > 1
                        % 线性拟合
                        [p, S] = polyfit(X_vals, y_vals, 1);
                        y_fit = polyval(p, X_vals);

                        % 计算R?
                        R2 = 1 - sum((y_vals - y_fit).^2) / sum((y_vals - mean(y_vals)).^2);

                        % 计算拟合统计信息
                        n = length(X_vals);
                        y_mean = mean(y_vals);
                        SSR = sum((y_fit - y_mean).^2);  % 回归平方和
                        SSE = sum((y_vals - y_fit).^2);  % 残差平方和
                        SST = sum((y_vals - y_mean).^2); % 总平方和
                        
                        % F统计量
                        F_stat = (SSR / (2-1)) / (SSE / (n-2));

                        % 回归模型的p值 (F检验)
                        p_model = 1 - fcdf(F_stat, 1, n-2);     
                        
                        % 计算标准误差
                        se_slope = sqrt(SSE / (n-2)) / sqrt(sum((X_vals - mean(X_vals)).^2));
                        se_intercept = sqrt(SSE / (n-2)) * sqrt(1/n + mean(X_vals)^2 / sum((X_vals - mean(X_vals)).^2));

                        % 计算t统计量
                        t_slope = p(1) / se_slope;
                        t_intercept = p(2) / se_intercept;

                        % 计算p值（双尾检验）
                        p_slope = 2 * (1 - tcdf(abs(t_slope), n-2));
                        p_intercept = 2 * (1 - tcdf(abs(t_intercept), n-2));
                        
                        % 绘图
                        scatter(appData.axes4, X_vals, y_vals, 'bo');
                        hold on;
                        plot(appData.axes4, X_vals, y_fit, 'r-', 'LineWidth', 2);
                        
                        % 计算R2
                        R2 = 1 - sum((y_vals - y_fit).^2) / sum((y_vals - mean(y_vals)).^2);
                        
                        indicatorNames = appData.raw(1,2:end);
                        indicatorName = indicatorNames{currentIndicator};
                        
                        % 【修改】标题包含模型显著性
                        if p_model < 0.001
                            p_model_str = '< 0.001';
                        else
                            p_model_str = sprintf('= %.4f', p_model);
                        end

                        title_str = sprintf('%s - Ratio Fit\nR^2 = %.4f, F-test p %s, n = %d', ...
                            indicatorName, R2, p_model_str, n);
                        title(appData.axes4, title_str);


                        xlabel_str = sprintf('Ex%.0fEm%.0f/Ex%.0fEm%.0f',...
                            bestPair(1), bestPair(2), bestPair(3), bestPair(4));
                        xlabel(appData.axes4, xlabel_str);
                        ylabel(appData.axes4, indicatorName);

                        % 【新增】在图上添加拟合方程和p值
                        equation_str = sprintf('y = %.4f*x + %.4f', p(1), p(2));
                        pvalue_str = sprintf('p(slope) = %.4f\np(intercept) = %.4f', p_slope, p_intercept);

                        % 选择合适的位置显示文本（右上角）
                        x_lim = xlim(appData.axes4);
                        y_lim = ylim(appData.axes4);
                        text_x = x_lim(1) + 0.05 * (x_lim(2) - x_lim(1));
                        text_y = y_lim(2) - 0.15 * (y_lim(2) - y_lim(1));

                        text(appData.axes4, text_x, text_y, equation_str, ...
                            'VerticalAlignment', 'top', 'FontSize', 8, ...
                            'BackgroundColor', 'none', 'EdgeColor', 'none');

                        text_y2 = y_lim(2) - 0.25 * (y_lim(2) - y_lim(1));
                        text(appData.axes4, text_x, text_y2, pvalue_str, ...
                            'VerticalAlignment', 'top', 'FontSize', 8, ...
                            'BackgroundColor', 'none', 'EdgeColor', 'none');

                        legend(appData.axes4, 'Data', 'Linear Fit', 'Location', 'best');
                        grid on;
                        hold off;                        
                        % 存储拟合数据
                        appData.currentFitData.X_vals = X_vals;
                        appData.currentFitData.y_vals = y_vals;
                        appData.currentFitData.y_fit = y_fit;
                        appData.currentFitData.R2 = R2;
                        appData.currentFitData.p = p;
                        appData.currentFitData.p_slope = p_slope;        % 【新增】
                        appData.currentFitData.p_intercept = p_intercept; % 【新增】
                        appData.currentFitData.n = n;                    % 【新增】
                        appData.currentFitData.equation_str = equation_str; % 【新增】                        
                        setappdata(fig, 'appData', appData);
                    end
                end
            else
                title(appData.axes4, 'No data available for fitting');
            end
        end
    end


    % 【新增】区域分析相关函数
    function plotRegionPPP(appData)

        % 绘制PPP二维散点图
        axes(appData.axes3);
        cla;
        if ~isfield(appData.regionData, 'PPP_2D') || isempty(appData.regionData.PPP_2D)
            appData.regionData.PPP_2D = struct('em', [], 'ex', [], 'ppp', [], 'size', [], 'range', []);
        end        
        if ~isempty(appData.PPP)
            % 将三维PPP数据转换为二维
            PPP_data = squeeze(appData.PPP(appData.IND,:,:));

            % 创建网格
            [Ex_grid, Em_grid] = meshgrid(appData.Ex, appData.Em);
            
            % 展平数据
            em_flat = Em_grid(:);
            ex_flat = Ex_grid(:);
            ppp_flat = PPP_data(:);
            
            % 过滤有效数据
            valid_idx = ppp_flat > 0;
            em_valid = em_flat(valid_idx);
            ex_valid = ex_flat(valid_idx);
            ppp_valid = ppp_flat(valid_idx);
          
            % 【修改】根据PPP数据的实际范围动态设置散点大小
            if ~isempty(ppp_valid)
                % 获取PPP值的范围
                ppp_min = min(ppp_valid);
                ppp_max = max(ppp_valid);
                ppp_range = ppp_max - ppp_min;
                
                % 设置基础大小和缩放因子
                base_size = 0.5;  % 最小散点大小
                scale_factor = 50;  % 大小缩放因子
                
                % 根据PPP值相对于范围的位置计算散点大小
                if ppp_range > 0
                    % 如果数据有变化范围，按比例缩放
                    normalized_ppp = (ppp_valid - ppp_min) / ppp_range;
                    scatter_size = base_size + scale_factor * normalized_ppp;
                else
                    % 如果所有PPP值相同，使用统一大小
                    scatter_size = base_size + scale_factor * 0.5 * ones(size(ppp_valid));
                end
                
                % 绘制散点图

                h_scatter = scatter(appData.axes3, em_valid, ex_valid, scatter_size, ppp_valid, 'filled');
                if isprop(h_scatter, 'PickableParts')
                    h_scatter.PickableParts = 'none';  % 新版本 MATLAB 推荐
                else
                    h_scatter.HitTest = 'off';         % 兼容旧版（但仍有风险）
                end                
                
                set(h_scatter, 'HitTest', 'off');  % 关键修改：禁用散点的鼠标事件拦截               
                colorbar;
                title(sprintf('%s - PPP Distribution (Region)\nRange: %.3f - %.3f', ...
                    appData.raw{1, appData.IND+1}, ppp_min, ppp_max));
                xlabel('Em (nm)');
                ylabel('Ex (nm)');
                
                % 【修改】设置坐标轴范围与plotPPP一致
                xlim(appData.axes3, [min(appData.Em), max(appData.Em)]);
                ylim(appData.axes3, [min(appData.Ex), max(appData.Ex)]);     

                % 存储二维PPP数据
                appData.regionData.PPP_2D.em = em_valid;
                appData.regionData.PPP_2D.ex = ex_valid;
                appData.regionData.PPP_2D.ppp = ppp_valid;
                appData.regionData.PPP_2D.size = scatter_size;
                appData.regionData.PPP_2D.range = [ppp_min, ppp_max]; % 存储范围信息
                
                setappdata(fig, 'appData', appData);
                set(appData.axes3, 'ButtonDownFcn', @startRegionSelection);

            else
                % 如果没有有效数据
                text(0.5, 0.5, 'No valid PPP data', ...
                    'HorizontalAlignment', 'center', 'Units', 'normalized');
                title('PPP Distribution (Region) - No Data');
                xlabel('Em (nm)');
                ylabel('Ex (nm)');
            end            

        
            % 存储二维PPP数据
%             appData.regionData.PPP_2D.em = em_valid;
%             appData.regionData.PPP_2D.ex = ex_valid;
%             appData.regionData.PPP_2D.ppp = ppp_valid;
%             appData.regionData.PPP_2D.size = scatter_size;

            % 设置框选回调
%             setappdata(fig, 'appData', appData);
%             set(appData.axes3, 'ButtonDownFcn', @startRegionSelection);

    % 设置框选回调
           
        end
    end

    function startRegionSelection(~, ~)      
       
        appData = getappdata(fig, 'appData');
        
        % 清理之前的定时器
        if ~isempty(appData.regionSelection.timerObj) && isvalid(appData.regionSelection.timerObj)
            stop(appData.regionSelection.timerObj);
            delete(appData.regionSelection.timerObj);
            appData.regionSelection.timerObj = [];
        end

        % 获取起始点
        cp = get(appData.axes3, 'CurrentPoint');
        startX = cp(1,1);
        startY = cp(1,2);

        
        % 【修复】存储起始点到appData中
        appData.regionSelection.startX = startX;
        appData.regionSelection.startY = startY;        
        
        % 创建临时矩形
        if ~isempty(appData.regionSelection.rect) && isvalid(appData.regionSelection.rect)
            delete(appData.regionSelection.rect);
        end
        appData.regionSelection.rect = rectangle('Parent', appData.axes3, ...
                         'Position', [startX, startY, 0, 0], ...
                         'EdgeColor', 'r', ...
                         'LineStyle', '--', ...
                         'LineWidth', 1.2);

        % 绑定移动和释放
        set(fig, 'WindowButtonMotionFcn', @onRegionMouseMove);
        set(fig, 'WindowButtonUpFcn', @onRegionMouseUp);
        setappdata(fig, 'appData', appData);
    end

    function onRegionMouseMove(~, ~)
        appData = getappdata(fig, 'appData');
        
        if isempty(appData.regionSelection.rect) || ~isvalid(appData.regionSelection.rect)
            return;
        end

        cp = get(appData.axes3, 'CurrentPoint');
        currX = cp(1,1); currY = cp(1,2);

        x_pos = min(appData.regionSelection.startX, currX);
        y_pos = min(appData.regionSelection.startY, currY);
        w = abs(currX - appData.regionSelection.startX);
        h = abs(currY - appData.regionSelection.startY);

        set(appData.regionSelection.rect, 'Position', [x_pos, y_pos, w, h]);
        drawnow limitrate;
    end

    function onRegionMouseUp(~, ~)
        appData = getappdata(fig, 'appData');

        % 清除鼠标事件
        set(fig, 'WindowButtonMotionFcn', []);
        set(fig, 'WindowButtonUpFcn', []);
        
        if isempty(appData.regionSelection.rect) || ~isvalid(appData.regionSelection.rect)
            return;
        end

        % 获取矩形范围
        pos = get(appData.regionSelection.rect, 'Position');
        x1 = pos(1); y1 = pos(2);
        x2 = x1 + pos(3); y2 = y1 + pos(4);
        x_min = min(x1, x2); x_max = max(x1, x2);
        y_min = min(y1, y2); y_max = max(y1, y2);

        % 判断选中点
        em_data = appData.regionData.PPP_2D.em;
        ex_data = appData.regionData.PPP_2D.ex;
        
        inRect = (em_data >= x_min) & (em_data <= x_max) & ...
                 (ex_data >= y_min) & (ex_data <= y_max);
         

        if any(inRect)
            % 存储选中的点
            appData.regionSelection.selectedPoints.em = em_data(inRect);
            appData.regionSelection.selectedPoints.ex = ex_data(inRect);
            appData.regionSelection.selectedPoints.ppp = appData.regionData.PPP_2D.ppp(inRect);
            
             % 【修改】计算选中点的实际波长范围
            selected_em = em_data(inRect);
            selected_ex = ex_data(inRect);
            
            em_min_selected = min(selected_em);
            em_max_selected = max(selected_em);
            ex_min_selected = min(selected_ex);
            ex_max_selected = max(selected_ex);   
            
            appData.regionSelection.selectedPoints.em_min_selected = em_min_selected;
            appData.regionSelection.selectedPoints.em_max_selected = em_max_selected;
            appData.regionSelection.selectedPoints.ex_min_selected = ex_min_selected;
            appData.regionSelection.selectedPoints.ex_max_selected = ex_max_selected;
            
            % 高亮显示选中的点
            hold(appData.axes3, 'on');
            scatter(appData.axes3, em_data(inRect), ex_data(inRect), ...
                    appData.regionData.PPP_2D.size(inRect), 'r', 'LineWidth', 1.5);
            hold(appData.axes3, 'off');
            
%             title(appData.axes3, sprintf('%s - PPP Distribution (Region) - %d points selected',...
%                 appData.raw{1, appData.IND+1},sum(inRect)));
        
            title_str = sprintf('%s - PPP Distribution (Region)\n%d points selected: Ex %.0f-%.0f nm, Em %.0f-%.0f nm', ...
                appData.raw{1, appData.IND+1}, sum(inRect), ex_min_selected, ex_max_selected, em_min_selected, em_max_selected);
            title(appData.axes3, title_str);            
            % 启动定时器自动恢复
            if ~isempty(appData.regionSelection.timerObj) && isvalid(appData.regionSelection.timerObj)
                delete(appData.regionSelection.timerObj);
            end
            appData.regionSelection.timerObj = timer('ExecutionMode', 'singleShot', ...
                             'StartDelay', 1.0, ...
                             'TimerFcn', @onRegionTimerCallback);
            start(appData.regionSelection.timerObj);

          
            % 更新其他区域分析图
            plotRegionCorrelation(appData);
            plotRegionBestFit(appData);
        else
            
            % 【新增】如果没有选中任何点，也显示矩形范围信息
            title_str = sprintf('%s - PPP Distribution (Region)\nNo points selected in region: Ex %.0f-%.0f nm, Em %.0f-%.0f nm', ...
                appData.raw{1, appData.IND+1}, y_min, y_max, x_min, x_max);
            title(appData.axes3, title_str);                                 
            % 启动定时器自动恢复
            if ~isempty(appData.regionSelection.timerObj) && isvalid(appData.regionSelection.timerObj)
                delete(appData.regionSelection.timerObj);
            end
            appData.regionSelection.timerObj = timer('ExecutionMode', 'singleShot', ...
                             'StartDelay', 1.0, ...
                             'TimerFcn', @onRegionTimerCallback);
            start(appData.regionSelection.timerObj);            
        end

        % 删除矩形
        delete(appData.regionSelection.rect);
        appData.regionSelection.rect = [];
        setappdata(fig, 'appData', appData);
    end

    function onRegionTimerCallback(~, ~)
        appData = getappdata(fig, 'appData');
        
        % 重新绘制PPP图以清除高亮
        plotRegionPPP(appData);

        appData.regionSelection.timerObj = [];
        setappdata(fig, 'appData', appData);
    end

    function plotRegionCorrelation(appData)
        % 绘制区域相关性图
        % 清除之前的K矩阵选择状态


%         appData.regionSelection.K_selectedPoints = struct('em', [], 'ex', [], 'k', []);       
        axes(appData.axes5);
        cla;
        
        if ~isempty(appData.regionSelection.selectedPoints)
            % 获取选中的点对应的em和ex索引
            selected_em = appData.regionSelection.selectedPoints.em;
            selected_ex = appData.regionSelection.selectedPoints.ex;
            
            % 初始化K矩阵
            K_matrix = zeros(appData.nEm, appData.nEx);
            count_matrix = zeros(appData.nEm, appData.nEx);
            
            % 处理每个选中的点（作为分母）
            for i = 1:length(selected_em)
                em_idx = find(appData.Em == selected_em(i));
                ex_idx = find(appData.Ex == selected_ex(i));
                
                if ~isempty(em_idx) && ~isempty(ex_idx)
                    % 获取当前分母对应的相关矩阵
                    RR = squeeze(appData.r(appData.IND,:,:,em_idx,ex_idx));
                    PP = squeeze(appData.p(appData.IND,:,:,em_idx,ex_idx));
                    
                    % 应用物理约束
                    for em1 = 1:appData.nEm    
                        for ex1 = 1:appData.nEx
                            if appData.Ex(ex1) <= 0.5 * appData.Em(em1) || appData.Ex(ex1) >= appData.Em(em1)
                               RR(em1,ex1) = NaN;    
                            end                            
                        end
                    end
                    
                    % 创建二值矩阵：满足条件的为1，否则为0
                    binary_matrix = zeros(size(RR));
                    valid_mask = (PP < appData.pv) & (abs(RR) > appData.rv) & ~isnan(RR);
                    binary_matrix(valid_mask) = 1;
                    
                    % 累加到K矩阵
                    K_matrix = K_matrix + binary_matrix;
                    count_matrix = count_matrix + (~isnan(binary_matrix));
                end
            end
            
            % 计算平均K矩阵
            valid_count = count_matrix;
            valid_count(valid_count == 0) = 1; % 避免除以0
            K_matrix = K_matrix ./ valid_count;
            
            % 应用DF阈值

            DF = str2double(get(appData.dfValueEdit, 'String'));
            K_matrix(K_matrix < DF) = NaN;
            
            % 绘制K矩阵
%             contourf(appData.Em, appData.Ex, K_matrix', ...
%                 'LineStyle', 'none', 'HitTest', 'off');
%             colorbar;
%             
%             title(sprintf('%s - Correlation Map\n(Ex %.0f-%.0f nm, Em %.0f-%.0f nm)',...
%                 appData.raw{1, appData.IND+1},...                
%                 appData.regionSelection.selectedPoints.ex_min_selected,...
%                 appData.regionSelection.selectedPoints.ex_max_selected,...
%                 appData.regionSelection.selectedPoints.em_min_selected,...
%                 appData.regionSelection.selectedPoints.em_max_selected));
%             xlabel('Em (nm)');
%             ylabel('Ex (nm)');            
            
            
        if ~isempty(K_matrix)
  
            % 创建网格
            [Ex_grid, Em_grid] = meshgrid(appData.Ex, appData.Em);
            
            % 展平数据
            em_flat = Em_grid(:);
            ex_flat = Ex_grid(:);
            k_flat = K_matrix(:);
            
            % 过滤有效数据（K值大于等于DF阈值）

            valid_idx =  k_flat >= DF;            
            em_valid = em_flat(valid_idx);
            ex_valid = ex_flat(valid_idx);
            k_valid = k_flat(valid_idx);
           
            % 根据K值设置散点大小
            if ~isempty(k_valid)
                % 获取K值的范围
                k_min = min(k_valid);
                k_max = max(k_valid);
                k_range = k_max - k_min;
                
                % 设置基础大小和缩放因子
                base_size = 0.5;  % 最小散点大小
                scale_factor = 20;  % 大小缩放因子
                
                % 根据K值相对于范围的位置计算散点大小
                if k_range > 0
                    % 如果数据有变化范围，按比例缩放
                    normalized_k = (k_valid - k_min) / k_range;
                    scatter_size = base_size + scale_factor * normalized_k;
                else
                    % 如果所有K值相同，使用统一大小
                    scatter_size = base_size + scale_factor * 0.5 * ones(size(k_valid));
                end
                
                % 绘制散点图，关闭HitTest避免拦截鼠标事件
                h_scatter = scatter(appData.axes5, em_valid, ex_valid, scatter_size, k_valid, 'filled');
                if isprop(h_scatter, 'PickableParts')
                    h_scatter.PickableParts = 'none';
                else
                    % 保持原样或设置为 'off'
                    set(h_scatter, 'HitTest', 'off');
                end
                
                colorbar;
                
            title(sprintf('%s - Correlation Map\n(Ex %.0f-%.0f nm, Em %.0f-%.0f nm)',...
                appData.raw{1, appData.IND+1},...                
                appData.regionSelection.selectedPoints.ex_min_selected,...
                appData.regionSelection.selectedPoints.ex_max_selected,...
                appData.regionSelection.selectedPoints.em_min_selected,...
                appData.regionSelection.selectedPoints.em_max_selected));                
%                 title(sprintf('%s - Correlation Map (Region)\nRange: %.3f - %.3f, DF: %.2f', ...
%                     appData.raw{1, appData.IND+1}, k_min, k_max, DF));
                xlabel('Em (nm)');
                ylabel('Ex (nm)');
                
                % 设置坐标轴范围与plotPPP一致
                xlim(appData.axes5, [min(appData.Em), max(appData.Em)]);
                ylim(appData.axes5, [min(appData.Ex), max(appData.Ex)]);
                
                % 存储K矩阵散点数据
                appData.regionData.K_scatter.em = em_valid;
                appData.regionData.K_scatter.ex = ex_valid;
                appData.regionData.K_scatter.k = k_valid;
                appData.regionData.K_scatter.size = scatter_size;
                appData.regionData.K_scatter.range = [k_min, k_max];
                % 设置框选回调
%                 set(appData.axes5, 'HitTest', 'on');
%                 set(appData.axes5, 'PickableParts', 'all');                
%                 set(appData.axes5, 'ButtonDownFcn', @startKRegionSelection);
%                 set(appData.axes5, 'ButtonDownFcn', @(~,~) startKRegionSelection());
                setappdata(fig, 'appData', appData);
                % 【新增】同时保存到全局变量
                globalKScatterData = struct();
                globalKScatterData = appData.regionData.K_scatter;
%                 tt = appData.regionData.K_scatter;
%                 save 1.mat  tt;
                set(appData.axes5, 'ButtonDownFcn', @startKRegionSelection); 

            else
                % 如果没有有效数据
                text(0.5, 0.5, sprintf('No K values >= DF (%.2f)', DF), ...
                    'HorizontalAlignment', 'center', 'Units', 'normalized');
                title(sprintf('%s - Correlation Map (Region)', appData.raw{1, appData.IND+1}));
                xlabel('Em (nm)');
                ylabel('Ex (nm)');
                
                % 设置坐标轴范围
                xlim(appData.axes5, [min(appData.Em), max(appData.Em)]);
                ylim(appData.axes5, [min(appData.Ex), max(appData.Ex)]);
            end
            
            
        else
            title(appData.axes5, 'K matrix not available');
            xlabel('Em (nm)');
            ylabel('Ex (nm)');
            
            % 设置坐标轴范围
            xlim(appData.axes5, [min(appData.Em), max(appData.Em)]);
            ylim(appData.axes5, [min(appData.Ex), max(appData.Ex)]);
            % 初始化K_scatter结构
            appData.regionData.K_scatter.em = [];
            appData.regionData.K_scatter.ex = [];
            appData.regionData.K_scatter.k = [];
            appData.regionData.K_scatter.size = [];
            appData.regionData.K_scatter.range = [];            
            
            
        end            
             
            
            % 存储K矩阵
            appData.regionData.K_matrix = K_matrix;     
            setappdata(fig, 'appData', appData);
      
        else
            title(appData.axes5, 'No region selected for correlation analysis');
             % 初始化K_scatter结构
            appData.regionData.K_scatter.em = [];
            appData.regionData.K_scatter.ex = [];
            appData.regionData.K_scatter.k = [];
            appData.regionData.K_scatter.size = [];
            appData.regionData.K_scatter.range = [];           
            setappdata(fig, 'appData', appData);
            
        end
        

    end


    % 【新增】K矩阵区域选择相关函数
    function startKRegionSelection(~,~)

        appData = getappdata(fig, 'appData');

        % 清理之前的定时器
        if ~isempty(appData.regionSelection.K_timerObj) && isvalid(appData.regionSelection.K_timerObj)
            stop(appData.regionSelection.K_timerObj);
            delete(appData.regionSelection.K_timerObj);
            appData.regionSelection.K_timerObj = [];
        end

        % 获取起始点
        cp = get(appData.axes5, 'CurrentPoint');
        startX = cp(1,1);
        startY = cp(1,2);

        % 存储起始点到appData中
        appData.regionSelection.K_startX = startX;
        appData.regionSelection.K_startY = startY;

        % 创建临时矩形
        if ~isempty(appData.regionSelection.K_rect) && isvalid(appData.regionSelection.K_rect)
            delete(appData.regionSelection.K_rect);
        end
        appData.regionSelection.K_rect = rectangle('Parent', appData.axes5, ...
                         'Position', [startX, startY, 0, 0], ...
                         'EdgeColor', 'r', ...
                         'LineStyle', '--', ...
                         'LineWidth', 1.2);
        
        % 设置矩形的HitTest为off，避免干扰
        set(appData.regionSelection.K_rect, 'HitTest', 'off');

        % 绑定移动和释放
       
        set(fig, 'WindowButtonMotionFcn', @onKRegionMouseMove);
        set(fig, 'WindowButtonUpFcn', @onKRegionMouseUp);        
        
        
        setappdata(fig, 'appData', appData);
    end

    function onKRegionMouseMove(~, ~)
        appData = getappdata(fig, 'appData');
        
        if isempty(appData.regionSelection.K_rect) || ~isvalid(appData.regionSelection.K_rect)
            return;
        end

        cp = get(appData.axes5, 'CurrentPoint');
        currX = cp(1,1); currY = cp(1,2);

        % 使用存储的起始点坐标
        x_pos = min(appData.regionSelection.K_startX, currX);
        y_pos = min(appData.regionSelection.K_startY, currY);
        w = abs(currX - appData.regionSelection.K_startX);
        h = abs(currY - appData.regionSelection.K_startY);

        set(appData.regionSelection.K_rect, 'Position', [x_pos, y_pos, w, h]);
        drawnow limitrate;
    end

    function onKRegionMouseUp(~, ~)
        appData = getappdata(fig, 'appData');
        
        % 清除鼠标事件
        set(fig, 'WindowButtonMotionFcn', []);
        set(fig, 'WindowButtonUpFcn', []);

        if isempty(appData.regionSelection.K_rect) || ~isvalid(appData.regionSelection.K_rect)
            return;
        end
        

        % 获取矩形范围
        pos = get(appData.regionSelection.K_rect, 'Position');
        x1 = pos(1); y1 = pos(2);
        x2 = x1 + pos(3); y2 = y1 + pos(4);
        x_min = min(x1, x2); x_max = max(x1, x2);
        y_min = min(y1, y2); y_max = max(y1, y2);
        
%         load('1.mat', 'tt');
%         appData.regionData.K_scatter = tt;

        if ~isempty(globalKScatterData) && ~isempty(globalKScatterData.em)
%             em_data = globalKScatterData.em;
%             ex_data = globalKScatterData.ex;
%             k_data = globalKScatterData.k;


%         判断选中点
          appData.regionData.K_scatter = globalKScatterData;
%         if isfield(appData.regionData, 'K_scatter') && ~isempty(appData.regionData.K_scatter)
%          检查函数   
%             
            em_data = appData.regionData.K_scatter.em;
            ex_data = appData.regionData.K_scatter.ex;
            k_data = appData.regionData.K_scatter.k;

            inRect = (em_data >= x_min) & (em_data <= x_max) & ...
                     (ex_data >= y_min) & (ex_data <= y_max);

            if any(inRect)
                % 存储选中的K矩阵点
                appData.regionSelection.K_selectedPoints.em = em_data(inRect);
                appData.regionSelection.K_selectedPoints.ex = ex_data(inRect);
                appData.regionSelection.K_selectedPoints.k = k_data(inRect);
                
                % 计算选中点的实际波长范围
                selected_em = em_data(inRect);
                selected_ex = ex_data(inRect);
                
                em_min_selected = min(selected_em);
                em_max_selected = max(selected_em);
                ex_min_selected = min(selected_ex);
                ex_max_selected = max(selected_ex);
                
                % 高亮显示选中的点
                hold(appData.axes5, 'on');
                h_highlight = scatter(appData.axes5, selected_em, selected_ex, ...
                        appData.regionData.K_scatter.size(inRect), 'r', 'LineWidth', 1.5);
                set(h_highlight, 'HitTest', 'off');
                hold(appData.axes5, 'off');
                
                % 更新标题，显示选中点数量和范围
                title_str = sprintf('%s - Correlation Map\n%d K points selected: Ex %.0f-%.0f nm, Em %.0f-%.0f nm', ...
                    appData.raw{1, appData.IND+1}, sum(inRect), ex_min_selected, ex_max_selected, em_min_selected, em_max_selected);
                title(appData.axes5, title_str);
                
                % 启动定时器自动恢复
                if ~isempty(appData.regionSelection.K_timerObj) && isvalid(appData.regionSelection.K_timerObj)
                    delete(appData.regionSelection.K_timerObj);
                end
                appData.regionSelection.K_timerObj = timer('ExecutionMode', 'singleShot', ...
                                 'StartDelay', 1.0, ...
                                 'TimerFcn',@onKRegionTimerCallback);
                start(appData.regionSelection.K_timerObj);
                
                % 更新axes6图（使用新选择的K矩阵点）
                plotRegionBestFit(appData);
            else
                % 如果没有选中任何点，也显示矩形范围信息
                title_str = sprintf('Correlation Map (Region)\nNo K points selected in region: Ex %.0f-%.0f nm, Em %.0f-%.0f nm', ...
                    y_min, y_max, x_min, x_max);
                title(appData.axes5, title_str);
            end
        end

        % 删除矩形
        delete(appData.regionSelection.K_rect);
        appData.regionSelection.K_rect = [];
        setappdata(fig, 'appData', appData);
    end

    function onKRegionTimerCallback(~,~)
        appData = getappdata(fig, 'appData');
        
        % 重新绘制K矩阵散点图以清除高亮
        plotRegionCorrelation(appData);
        
        appData.regionSelection.K_timerObj = [];
        setappdata(fig, 'appData', appData);
    end


    function plotRegionBestFit(appData)
        % 绘制区域最佳拟合图
        axes(appData.axes6);
        cla;
        hasPPPPoints = ~isempty(appData.regionSelection.selectedPoints);
        hasKPoints = ~isempty(appData.regionSelection.K_selectedPoints);
        
        if hasPPPPoints && (hasKPoints || ~isempty(appData.regionData.K_matrix))        
            % 获取选中的PPP点
            ppp_em = appData.regionSelection.selectedPoints.em;
            ppp_ex = appData.regionSelection.selectedPoints.ex;
            
            % 获取分子区域数据（优先使用新选择的K矩阵点，如果没有则使用原来的K矩阵点）
            if hasKPoints
                % 使用新选择的K矩阵点
                k_em = appData.regionSelection.K_selectedPoints.em;
                k_ex = appData.regionSelection.K_selectedPoints.ex;
                source_info = 'Manually Selected K Points';
            else
                % 使用原来的K矩阵点（大于DF的点）
                K_matrix = appData.regionData.K_matrix;
                DF = str2double(get(appData.dfValueEdit, 'String'));
                [k_em_idx, k_ex_idx] = find(~isnan(K_matrix) & K_matrix >= DF);
                k_em = appData.Em(k_em_idx);
                k_ex = appData.Ex(k_ex_idx);
                source_info = 'Auto K Matrix Points (DF threshold)';
            end
            
%             % 获取K矩阵中大于DF的点
%             K_matrix = appData.regionData.K_matrix;
%             DF = str2double(get(appData.dfValueEdit, 'String'));
%             [k_em_idx, k_ex_idx] = find(~isnan(K_matrix) & K_matrix >= DF);
%             k_em = appData.Em(k_em_idx);
%             k_ex = appData.Ex(k_ex_idx);
            
            if ~isempty(ppp_em) && ~isempty(k_em)
                % 找到共同项目
                commonItems = intersect(appData.EEM_dataname, appData.IF_dataname);
                [~, idx1] = ismember(commonItems, appData.EEM_dataname);
                
                % 计算EEM比值
                X = appData.Results.EEM.X(idx1,:,:);
                
                % 计算分子和分母的均值荧光
                % 分子：K矩阵中大于DF的点对应的荧光均值
                % 分母：PPP选中的点对应的荧光均值
                
                % 计算分子荧光均值
                numerator_fluo = zeros(size(X,1), 1);
%                 for i = 1:length(k_em_idx)
%                     em_idx = k_em_idx(i);
%                     ex_idx = k_ex_idx(i);
%                     numerator_fluo = numerator_fluo + squeeze(X(:, em_idx, ex_idx));
%                 end
                for i = 1:length(k_em)
                    em_idx = find(appData.Em == k_em(i));
                    ex_idx = find(appData.Ex == k_ex(i));
                    if ~isempty(em_idx) && ~isempty(ex_idx)
                        numerator_fluo = numerator_fluo + squeeze(X(:, em_idx, ex_idx));
                    end
                end               
                numerator_fluo = numerator_fluo / length(k_em);
                
                % 计算分母荧光均值
                denominator_fluo = zeros(size(X,1), 1);
                for i = 1:length(ppp_em)
                    em_idx = find(appData.Em == ppp_em(i));
                    ex_idx = find(appData.Ex == ppp_ex(i));
                    if ~isempty(em_idx) && ~isempty(ex_idx)
                        denominator_fluo = denominator_fluo + squeeze(X(:, em_idx, ex_idx));
                    end
                end
                denominator_fluo = denominator_fluo / length(ppp_em);
                
                % 计算比值
                X_vals = numerator_fluo ./ denominator_fluo;
                y_vals = appData.IF_r(:, appData.IND);
                
                valid_idx = ~isnan(X_vals) & ~isnan(y_vals) & ~isinf(X_vals);
                X_vals = X_vals(valid_idx);
                y_vals = y_vals(valid_idx);
                
                if length(X_vals) > 1
                    % 线性拟合
                    [p, S] = polyfit(X_vals, y_vals, 1);
                    y_fit = polyval(p, X_vals);
                    
                    % 绘图
                    scatter(appData.axes6, X_vals, y_vals, 'bo');
                    hold on;
                    plot(appData.axes6, X_vals, y_fit, 'r-', 'LineWidth', 2);
                    
                    % 计算R?
                    R2 = 1 - sum((y_vals - y_fit).^2) / sum((y_vals - mean(y_vals)).^2);
                    
                    % 计算拟合统计信息
                    n = length(X_vals);
                    y_mean = mean(y_vals);
                    SSR = sum((y_fit - y_mean).^2);
                    SSE = sum((y_vals - y_fit).^2);
                    SST = sum((y_vals - y_mean).^2);
                    
                    % F统计量
                    F_stat = (SSR / (2-1)) / (SSE / (n-2));
                    p_model = 1 - fcdf(F_stat, 1, n-2);
                    
                    indicatorNames = appData.raw(1,2:end);
                    indicatorName = indicatorNames{appData.IND};
                    
                    % 标题
                    if p_model < 0.001
                        p_model_str = '< 0.001';
                    else
                        p_model_str = sprintf('= %.4f', p_model);
                    end
                    
                    title_str = sprintf('%s - Ratio Fit (Ex=%d - %d, Em=%d - %d nm)\nR^2 = %.4f, F-test p %s, n = %d', ...
                         indicatorName,min(k_ex), max(k_ex), min(k_em), max(k_em), R2, p_model_str, n);
                    title(appData.axes6, title_str);
                    
                    xlabel(appData.axes6, 'Region Ratio');
                    ylabel(appData.axes6, indicatorName);
                    
                    % 添加拟合方程
                    equation_str = sprintf('y = %.4f*x + %.4f', p(1), p(2));
                    x_lim = xlim(appData.axes6);
                    y_lim = ylim(appData.axes6);
                    text_x = x_lim(1) + 0.05 * (x_lim(2) - x_lim(1));
                    text_y = y_lim(2) - 0.15 * (y_lim(2) - y_lim(1));
                    
                    text(appData.axes6, text_x, text_y, equation_str, ...
                        'VerticalAlignment', 'top', 'FontSize', 10, ...
                        'BackgroundColor', 'none', 'EdgeColor', 'none');
                    
                    legend(appData.axes6, 'Data', 'Linear Fit', 'Location', 'best');
                    grid on;
                    hold off;
                else
                    title(appData.axes6, 'Not enough valid data for region fitting');
                end
            else
                title(appData.axes6, 'No valid points for region fitting');
            end
        else
            title(appData.axes6, 'No region data available for fitting');
        end
    end



    function exportFitDataCallback(~, ~)
        appData = getappdata(fig, 'appData');
        
        % 检查是否有拟合数据可导出（包括axes4和axes6）
        hasAxes4Data = ~isempty(appData.currentFitData) && ~isempty(appData.currentFitData.X_vals);
        hasAxes6Data = (~isempty(appData.regionSelection.selectedPoints) && ~isempty(appData.regionData.K_matrix)) || ...
                       (~isempty(appData.regionSelection.selectedPoints) && ~isempty(appData.regionSelection.K_selectedPoints));        
        
        if ~hasAxes4Data && ~hasAxes6Data
            msgbox('No fit data to export! Please select wavelengths first or perform region analysis.', 'Warning', 'warn');
            return;
        end
        
        [filename, pathname] = uiputfile('*.xlsx', 'Save Fit Data As');
        if filename ~= 0
            fullpath = fullfile(pathname, filename);
            
            % 导出axes4的拟合数据（原有功能）
            if hasAxes4Data            % 准备数据
                ratio_str = sprintf('Ex%.0fEm%.0f/Ex%.0fEm%.0f', ...
                    appData.currentSelection.Ex2, appData.currentSelection.Em2, ...
                    appData.currentSelection.Ex1, appData.currentSelection.Em1);

                indicatorNames = appData.raw(1,2:end);
                indicatorName = indicatorNames{appData.IND};

                fit_data = [appData.currentFitData.X_vals, appData.currentFitData.y_vals, appData.currentFitData.y_fit];
                headers = {ratio_str, indicatorName, 'Fitted_Value'};

                % 写入Excel
                xlswrite(fullpath,[headers; num2cell(fit_data)],'Fit_Data');
    %             writetable(array2table(fit_data, 'VariableNames', headers), fullpath);

                % 添加拟合参数到第二个sheet
                params = [appData.currentFitData.p(1), appData.currentFitData.p(2), appData.currentFitData.R2];
                param_headers = {'Slope', 'Intercept', 'R2'};

                try
                    warning('off', 'MATLAB:xlswrite:AddSheet');
                    writetable(array2table(params, 'VariableNames', param_headers), fullpath, 'Sheet', 'Fit_Parameters');
                catch
                    % 如果无法写入第二个sheet，忽略错误
                end
            end
            
            % 【新增】导出axes6的区域荧光数据（仿照axes4的方式）
            if hasAxes6Data
                try
                    warning('off', 'MATLAB:xlswrite:AddSheet');
                    
                    % 获取分子区域数据
                    denominator_em = appData.regionSelection.selectedPoints.em;
                    denominator_ex = appData.regionSelection.selectedPoints.ex;
                    denominator_ppp = appData.regionSelection.selectedPoints.ppp;
                    
                    % 【修改】获取分子区域数据（优先使用手动选择的K矩阵点）
                    if ~isempty(appData.regionSelection.K_selectedPoints)
                        % 使用手动选择的K矩阵点
                        numerator_em = appData.regionSelection.K_selectedPoints.em;
                        numerator_ex = appData.regionSelection.K_selectedPoints.ex;
                        numerator_k = appData.regionSelection.K_selectedPoints.k;
                        selection_source = 'Manually Selected K Points';
                    else
                        % 使用原来的K矩阵点（大于DF的点）
                        K_matrix = appData.regionData.K_matrix;
                        DF = str2double(get(appData.dfValueEdit, 'String'));
                        [k_em_idx, k_ex_idx] = find(~isnan(K_matrix) & K_matrix >= DF);
                        numerator_em = appData.Em(k_em_idx);
                        numerator_ex = appData.Ex(k_ex_idx);
                        numerator_k = K_matrix(~isnan(K_matrix) & K_matrix >= DF);
                        selection_source = 'Auto K Matrix Points (DF threshold)';
                    end                    
%                     
%                     K_matrix = appData.regionData.K_matrix;
                    DF = str2double(get(appData.dfValueEdit, 'String'));
%                     [k_em_idx, k_ex_idx] = find(~isnan(K_matrix) & K_matrix >= DF);
%                     numerator_em = appData.Em(k_em_idx);
%                     numerator_ex = appData.Ex(k_ex_idx);
%                     numerator_K = K_matrix(~isnan(K_matrix) & K_matrix >= DF);
                    
                    % 找到共同项目
                    commonItems = intersect(appData.EEM_dataname, appData.IF_dataname);
                    [~, idx1] = ismember(commonItems, appData.EEM_dataname);
                    X = appData.Results.EEM.X(idx1,:,:);
                    
                    % 计算比值数据（与plotRegionBestFit中相同的计算逻辑）
                    numerator_fluo = zeros(size(X,1), 1);
%                     for i = 1:length(k_em_idx)
%                         em_idx = k_em_idx(i);
%                         ex_idx = k_ex_idx(i);
%                         numerator_fluo = numerator_fluo + squeeze(X(:, em_idx, ex_idx));
%                     end
                    for i = 1:length(numerator_em)
                        em_idx = find(appData.Em == numerator_em(i));
                        ex_idx = find(appData.Ex == numerator_ex(i));
                        if ~isempty(em_idx) && ~isempty(ex_idx)
                            numerator_fluo = numerator_fluo + squeeze(X(:, em_idx, ex_idx));
                        end
                    end
                    numerator_fluo = numerator_fluo / length(numerator_em);
                    
                    denominator_fluo = zeros(size(X,1), 1);
                    for i = 1:length(denominator_em)
                        em_idx = find(appData.Em == denominator_em(i));
                        ex_idx = find(appData.Ex == denominator_ex(i));
                        if ~isempty(em_idx) && ~isempty(ex_idx)
                            denominator_fluo = denominator_fluo + squeeze(X(:, em_idx, ex_idx));
                        end
                    end
                    denominator_fluo = denominator_fluo / length(denominator_em);
                    
                    X_vals = numerator_fluo ./ denominator_fluo;
                    y_vals = appData.IF_r(:, appData.IND);
                    
                    valid_idx = ~isnan(X_vals) & ~isnan(y_vals) & ~isinf(X_vals);
                    X_vals_valid = X_vals(valid_idx);
                    y_vals_valid = y_vals(valid_idx);
                    
                    if length(X_vals_valid) > 1
                        % 线性拟合（与plotRegionBestFit中相同的拟合）
                        [p, S] = polyfit(X_vals_valid, y_vals_valid, 1);
                        y_fit = polyval(p, X_vals_valid);
                        
                        % 准备拟合数据（仿照axes4的格式）
                        fit_data = [X_vals_valid, y_vals_valid, y_fit];
                        headers = {'Region_Ratio', appData.raw{1, appData.IND+1}, 'Fitted_Value'};
                        
                        % 写入拟合数据
                        xlswrite(fullpath, [headers; num2cell(fit_data)], 'Region_Ratio_Fit_Data');   
                        
                        % 计算R?
                        R2 = 1 - sum((y_vals_valid - y_fit).^2) / sum((y_vals_valid - mean(y_vals_valid)).^2);
                        
                        % 写入拟合参数
                        params = [p(1), p(2), R2];
                        param_headers = {'Slope', 'Intercept', 'R2'};
                        xlswrite(fullpath, [param_headers; num2cell(params)], 'Region_Ratio_Fit_Parameters');                        
                    end
                    
                    % 准备分母区域荧光数据
                    denominator_fluo_data = zeros(length(commonItems), length(denominator_em));
                    for i = 1:length(commonItems)
                        for j = 1:length(denominator_em)
                            em_idx = find(appData.Em == denominator_em(j));
                            ex_idx = find(appData.Ex == denominator_ex(j));
                            if ~isempty(em_idx) && ~isempty(ex_idx)
                                denominator_fluo_data(i, j) = squeeze(X(i, em_idx, ex_idx));
                            end
                        end
                    end
                    
                    % 创建分母区域表格
                    denominator_table = array2table(denominator_fluo_data);
                    wavelength_names_den = cell(1, length(denominator_em));
                    for i = 1:length(denominator_em)
                        wavelength_names_den{i} = sprintf('Ex%.0f_Em%.0f', denominator_ex(i), denominator_em(i));
                    end
                    denominator_table.Properties.VariableNames = wavelength_names_den;
                    denominator_table.Sample_Name = commonItems;
                    
                    % 重新排列列顺序，将Sample_Name放在第一列
                    denominator_table = movevars(denominator_table, 'Sample_Name', 'Before', 1);
                    writetable(denominator_table, fullpath, 'Sheet', 'Region_Denominator_Fluorescence');
                    
                    % 准备分子区域荧光数据
                    numerator_fluo_data = zeros(length(commonItems), length(numerator_em));
                    for i = 1:length(commonItems)
                        for j = 1:length(numerator_em)
                            em_idx = find(appData.Em == numerator_em(j));
                            ex_idx = find(appData.Ex == numerator_ex(j));
                            if ~isempty(em_idx) && ~isempty(ex_idx)
                                numerator_fluo_data(i, j) = squeeze(X(i, em_idx, ex_idx));
                            end
                        end
                    end
                    
                    % 创建分子区域表格
                    numerator_table = array2table(numerator_fluo_data);
                    wavelength_names_num = cell(1, length(numerator_em));
                    for i = 1:length(numerator_em)
                        wavelength_names_num{i} = sprintf('Ex%.0f_Em%.0f', numerator_ex(i), numerator_em(i));
                    end
                    numerator_table.Properties.VariableNames = wavelength_names_num;
                    numerator_table.Sample_Name = commonItems;
                    
                    % 重新排列列顺序，将Sample_Name放在第一列
                    numerator_table = movevars(numerator_table, 'Sample_Name', 'Before', 1);
                    writetable(numerator_table, fullpath, 'Sheet', 'Region_Numerator_Fluorescence');
                    
                    % 写入区域信息摘要
                    region_summary = {
                        'Region Analysis Summary', '';
                        'Export Time:', datestr(now, 'yyyy-mm-dd HH:MM:SS');
                        '', '';
                        'Denominator Region (PPP Selected Points):', '';
                        sprintf('Number of wavelength pairs: %d', length(denominator_em)), '';
                        sprintf('Excitation range: %.0f-%.0f nm', min(denominator_ex), max(denominator_ex)), '';
                        sprintf('Emission range: %.0f-%.0f nm', min(denominator_em), max(denominator_em)), '';
                        sprintf('PPP value range: %.4f-%.4f', min(denominator_ppp), max(denominator_ppp)), '';
                        '', '';
                        'Numerator Region (K Matrix Selected Points):', '';
                        sprintf('Number of wavelength pairs: %d', length(numerator_em)), '';
                        sprintf('Excitation range: %.0f-%.0f nm', min(numerator_ex), max(numerator_ex)), '';
                        sprintf('Emission range: %.0f-%.0f nm', min(numerator_em), max(numerator_em)), '';
                        sprintf('K value range: %.4f-%.4f', min(numerator_k), max(numerator_k)), '';
                        '', '';
                        'Calculation Parameters:', '';
                        sprintf('DF threshold: %.2f', DF), '';
                        sprintf('Indicator: %s', appData.raw{1, appData.IND+1}), '';
                        sprintf('Total samples: %d', length(commonItems)), '';
                        sprintf('Valid samples for fitting: %d', sum(valid_idx)), '';
                        sprintf('Calculation: Mean(Numerator_Fluorescence) / Mean(Denominator_Fluorescence)'), '';
                    };
                    

                    xlswrite(fullpath, region_summary, 'Region_Analysis_Summary');         
                    
                catch ME
                    warning('Failed to export region data: %s', ME.message);
                    msgbox(sprintf('Error exporting region data: %s', ME.message), 'Error', 'error');
                end
            end            
            
            
            msgbox(sprintf('Fit data exported successfully to:\n%s', fullpath), 'Success');
        end
    end


   

    function exportResultsCallback(~, ~)
        appData = getappdata(fig, 'appData');
        
        if isempty(appData.Ind_output)
            msgbox('No results to export!', 'Warning', 'warn');
            return;
        end
        
        [filename, pathname] = uiputfile('*.xlsx', 'Save Results As');
        if filename ~= 0
            fullpath = fullfile(pathname, filename);
            tableData = array2table(appData.Ind_output,...
                'VariableNames', {'Ex_num', 'Em_num', 'Ex_den', 'Em_den', 'R_value', 'P_value','Indicator_index'});
            writetable(tableData, fullpath, 'Sheet', 'Main_Results');
            
            % 保存详细信息到第二个sheet
            if size(appData.Ind_output, 1) > 0
                [~, sortIdx] = sort(appData.Ind_output(:,6));
                topPairs = appData.Ind_output(sortIdx(1:min(10, end)), :);
                topTable = array2table(topPairs,...
                    'VariableNames', {'Ex_num', 'Em_num', 'Ex_den', 'Em_den', 'R_value', 'P_value','Indicator_index'});
                
                try
                    warning('off', 'MATLAB:xlswrite:AddSheet');
                    writetable(topTable, fullpath, 'Sheet', 'Top10_Pairs');
                catch
                    % 如果无法写入第二个sheet，忽略错误
                end
            end
            
            msgbox(sprintf('Results exported successfully to:\n%s', fullpath), 'Success');
        end
    end

    function resetGUI(~, ~)
        % 重置所有参数
%         appData = getappdata(fig, 'appData');
        % 直接从图形对象获取appData
        figHandle = findobj('Type', 'figure', 'Name', '3D-EEM Ratio Analyzer');
        if isempty(figHandle)
            return;
        end
        appData = getappdata(figHandle, 'appData');        
        % 重置UI元素
        set(appData.eemPathEdit, 'String', 'EEM_parafac_results_data.mat');
        set(appData.indicatorPathEdit, 'String', 'Indicator_data.xlsx');
        set(appData.dataStatusLamp, 'BackgroundColor', [0.5, 0.5, 0.5]);
        set(appData.dataInfoText, 'String', {'Click "Load All Data" to begin...'}, 'Value', 1);
        set(appData.pValueEdit, 'String', '0.01');
        set(appData.rValueEdit, 'String', '0.6');
        set(appData.dfValueEdit, 'String', '0.5'); % 【新增】        
        set(appData.progressLamp, 'BackgroundColor', [0.5, 0.5, 0.5]);
        set(appData.progressText, 'String', 'Ready for calculation');
        set(appData.calcInfoText, 'String', {'No calculation performed yet.'}, 'Value', 1);
        set(appData.resultsTable, 'Data', []);
        set(appData.bestRatioText, 'String', {'Results will appear here after calculation.'}, 'Value', 1);
        set(appData.detailedResultsText, 'String', {'No detailed results available.'}, 'Value', 1);

         % 【新增】确保新添加的字段也被重置
        if isfield(appData, 'saveDataBtn')
            % 按钮已经存在，不需要重新创建
        end       
        
        % 清除数据
        appData.dataLoaded = false;
        appData.calculationDone = false;
        appData.Results = [];
        appData.IF_r = [];
        appData.r = [];
        appData.p = [];
        appData.exm = [];
        appData.PPP = [];
        appData.Ind_output = [];
        appData.currentSelection = struct('Ex1', [], 'Em1', [], 'Ex2', [], 'Em2', [], ...
                                         'idxEx1', [], 'idxEm1', [], 'idxEx2', [], 'idxEm2', []);
        appData.currentFitData = [];
        
        % 【新增】清除区域选择数据
%         appData.regionSelection = struct('selectedPoints', [], 'rect', [], 'timerObj', []);
%         appData.regionData = struct('PPP_2D', [], 'K_matrix', [], 'selectedIndices', []);      
        appData.regionSelection = struct(...
            'selectedPoints', struct('em', [], 'ex', [], 'ppp', []), ...
            'rect', [], ...
            'timerObj', [], ...
            'startX', [], ...
            'startY', [], ...
            'K_selectedPoints', struct('em', [], 'ex', [], 'k', []), ...
            'K_rect', [], ...
            'K_timerObj', [], ...
            'K_startX', [], ...
            'K_startY', [] ...
        );
        
        appData.regionData = struct(...
            'PPP_2D', struct('em', [], 'ex', [], 'ppp', [], 'size', [], 'range', []),...
            'K_matrix', [], ...
            'K_scatter', struct('em', [], 'ex', [], 'k', [], 'size', [], 'range', []) ...
        );
    
        % 清除图形
        cla(appData.axes1);
        cla(appData.axes2);
        cla(appData.axes3);
        cla(appData.axes4);
        cla(appData.axes5);
        cla(appData.axes6);        
        
        
        % 重置下拉菜单
%         set(appData.indicatorPopup, 'String', {'Select indicator...'});
        set(appData.visIndicatorPopup, 'String', {'Select indicator...'});
        
%         setappdata(fig, 'appData', appData);
        setappdata(figHandle, 'appData', appData);
        msgbox('GUI reset successfully!', 'Reset Complete');
    end

    function closeGUI(~, ~)
        selection = questdlg('Are you sure you want to close?', ...
            'Confirm Close', ...
            'Yes', 'No', 'Yes');
        if strcmp(selection, 'Yes')
            % 【新增】清理定时器
            appData = getappdata(fig, 'appData');
            if ~isempty(appData.regionSelection.timerObj) && isvalid(appData.regionSelection.timerObj)
                stop(appData.regionSelection.timerObj);
                delete(appData.regionSelection.timerObj);
            end
            close(fig);            
        end
    end

end


 function updateResultsTable(appData)
%         fig = findobj('Type', 'figure', 'Name', '3D-EEM Ratio Analyzer');
%         if isempty(fig)
%             return;
%         end
%         appData = getappdata(fig, 'appData');

        if ~isfield(appData, 'Ind_output') || isempty(appData.Ind_output)
            set(appData.resultsTable, 'Data', []);
            set(appData.bestRatioText, 'String', {'No significant pairs found for any indicator.'}, 'Value', 1);
            set(appData.detailedResultsText, 'String', {'No significant pairs found with current thresholds.'}, 'Value', 1);
            return;
        end        
        tableData = appData.Ind_output;
     
        set(appData.resultsTable, 'Data', tableData, ...
            'ColumnName', {'Ex_num', 'Em_num', 'Ex_den', 'Em_den', 'R_value', 'P_value', 'Indicator_Index'});
    
    
        if ~isempty(appData.Ind_output)
            tableData = appData.Ind_output;
            % 更新列名以包含指标索引
            set(appData.resultsTable, 'Data', tableData, ...
                'ColumnName', {'Ex_num', 'Em_num', 'Ex_den', 'Em_den', 'R_value', 'P_value', 'Indicator_Index'});
            
            % 找到最佳比值对（所有指标中p值最小的）
            if size(appData.Ind_output, 2) >= 7
%                 [~, bestIdx] = min(appData.Ind_output(:,6));
%                 bestPair = appData.Ind_output(bestIdx,:);
%                 indicatorNames = appData.raw(1,2:end);
%                 indicatorName = 'Unknown';
%                 if bestPair(7) <= length(indicatorNames)
%                     indicatorName = indicatorNames{bestPair(7)};
%                 end
%                 
%                 infoStr = {...
%                     'Best Ratio Pair (All Indicators):', ...
%                     '', ...
%                     sprintf('Indicator: %s', indicatorName), ...
%                     sprintf('Numerator: Ex %.0f nm, Em %.0f nm', bestPair(1), bestPair(2)), ...
%                     sprintf('Denominator: Ex %.0f nm, Em %.0f nm', bestPair(3), bestPair(4)), ...
%                     sprintf('Correlation (r): %.3f', bestPair(5)), ...
%                     sprintf('P-value: %.2e', bestPair(6)), ...
%                     '', ...
%                     sprintf('Total significant pairs: %d', size(appData.Ind_output, 1))};
%                 set(appData.bestRatioText, 'String', infoStr);

    indicatorNames = appData.raw(1,2:end);
    nIndicators = length(indicatorNames);
    
    % 为每个指标找到最佳波长对
    bestPairsInfo = cell(0); % 使用cell数组存储信息
    for ind = 1:nIndicators
        % 获取当前指标的所有显著对
        indicatorPairs = appData.Ind_output(appData.Ind_output(:,7) == ind, :);
        if ~isempty(indicatorPairs)
            % 找到p值最小的波长对
            [~, bestIdx] = min(indicatorPairs(:,6));
            bestPair = indicatorPairs(bestIdx,:);
            
            % 将信息存储在cell数组中
            bestPairsInfo{end+1, 1} = ind; % 指标索引
            bestPairsInfo{end, 2} = indicatorNames{ind}; % 指标名称
            bestPairsInfo{end, 3} = bestPair; % 最佳波长对
            bestPairsInfo{end, 4} = size(indicatorPairs, 1); % 显著对数量
        end
    end
    
    % 构建显示字符串
    if ~isempty(bestPairsInfo)
        infoStr = {'Best Ratio Pairs by Indicator:', ''};
        
        % 按指标名称排序，便于查看
        [~, sortIdx] = sort(bestPairsInfo(:,2));
        bestPairsInfo = bestPairsInfo(sortIdx, :);
        
        for i = 1:size(bestPairsInfo, 1)
            ind = bestPairsInfo{i, 1};
            indicatorName = bestPairsInfo{i, 2};
            pair = bestPairsInfo{i, 3};
            numPairs = bestPairsInfo{i, 4};
            
            infoStr{end+1} = sprintf('%s:', indicatorName);
            infoStr{end+1} = sprintf('  Numerator: Ex%.0f nm, Em%.0f nm', pair(1), pair(2));
            infoStr{end+1} = sprintf('  Denominator: Ex%.0f nm, Em%.0f nm', pair(3), pair(4));
            infoStr{end+1} = sprintf('  Correlation (r): %.3f', pair(5));
            infoStr{end+1} = sprintf('  P-value: %.2e', pair(6));
            infoStr{end+1} = sprintf('  Total significant pairs: %d', numPairs);
            infoStr{end+1} = '';
        end
        
        % 添加总结信息
        infoStr{end+1} = sprintf('Summary: Found best pairs for %d out of %d indicators', ...
            size(bestPairsInfo, 1), nIndicators);
        infoStr{end+1} = sprintf('Total significant wavelength pairs: %d', size(appData.Ind_output, 1));
    else
        infoStr = {'No significant pairs found for any indicator.'};
    end
    
    set(appData.bestRatioText, 'String', infoStr, 'Value', 1);               
                
                
                % 更新详细结果
                detailedStr = {};
                detailedStr{1} = 'DETAILED RESULTS SUMMARY (ALL INDICATORS):';
                detailedStr{2} = '===================================';
                detailedStr{3} = sprintf('P-value threshold: %.3f', appData.pv);
                detailedStr{4} = sprintf('R-value threshold: %.3f', appData.rv);
                detailedStr{5} = sprintf('Total Indicators: %d', size(appData.IF_r,2));
                detailedStr{6} = sprintf('Significant pairs found: %d', size(appData.Ind_output, 1));
                detailedStr{7} = '';
                detailedStr{8} = 'Significant Pairs by Indicator:';
                detailedStr{9} = '---------------------------';
                
                % 统计每个指标的显著对数量
                nIndicators = size(appData.IF_r, 2);
                pairsPerIndicator = zeros(nIndicators, 1);
                for ind = 1:nIndicators
                    pairsPerIndicator(ind) = sum(appData.Ind_output(:,7) == ind);
                    if pairsPerIndicator(ind) > 0
                        indicatorName = appData.raw{1, ind+1};
                        detailedStr{end+1} = sprintf('%s: %d pairs', indicatorName, pairsPerIndicator(ind));
                    end
                end
                
                detailedStr{end+1} = '';
                detailedStr{end+1} = 'Top 10 Most Significant Pairs (All Indicators):';
                detailedStr{end+1} = '------------------------------------';
                
                % 按p值排序并显示前10个
                if size(appData.Ind_output, 1) > 0
                    [~, sortIdx] = sort(appData.Ind_output(:,6));
                    for i = 1:min(10, length(sortIdx))
                        pair = appData.Ind_output(sortIdx(i),:);
                        indicatorName = 'Unknown';
                        if pair(7) <= length(indicatorNames)
                            indicatorName = indicatorNames{pair(7)};
                        end
                        detailedStr{end+1} = sprintf('%d. %s: Ex%.0f/Em%.0f ÷ Ex%.0f/Em%.0f: r=%.3f, p=%.2e', ...
                            i, indicatorName, pair(1), pair(2), pair(3), pair(4), pair(5), pair(6));
                    end
                end
 
                detailedStr{end+1} = '';
                detailedStr{end+1} = 'Top Significant Pairs by Indicator:';
                detailedStr{end+1} = '------------------------------------';
                
                % 为每个指标显示前10个（或实际个数）显著波长对
                nIndicators = size(appData.IF_r, 2);
                for ind = 1:nIndicators
                    % 获取当前指标的所有显著对
                    indicatorPairs = appData.Ind_output(appData.Ind_output(:,7) == ind, :);
                    if ~isempty(indicatorPairs)
                        indicatorName = appData.raw{1, ind+1};
                        detailedStr{end+1} = '';
                        detailedStr{end+1} = sprintf('%s:', indicatorName);
                        
                        % 按p值排序
                        [~, sortIdx] = sort(indicatorPairs(:,6));
                        sortedPairs = indicatorPairs(sortIdx, :);
                        
                        % 显示前10个或实际个数
                        numToShow = min(10, size(sortedPairs, 1));
                        for i = 1:numToShow
                            pair = sortedPairs(i,:);
                            detailedStr{end+1} = sprintf('  %d. Ex%.0f/Em%.0f ÷ Ex%.0f/Em%.0f: r=%.3f, p=%.2e', ...
                                i, pair(1), pair(2), pair(3), pair(4), pair(5), pair(6));
                        end
                        
                        % 如果实际个数少于10，显示实际个数
                        if size(sortedPairs, 1) < 10
                            detailedStr{end+1} = sprintf('  (Showing all %d significant pairs)', size(sortedPairs, 1));
                        end
                    end
                end               
                
                
                
                set(appData.detailedResultsText, 'String', detailedStr, 'Value', 1);
            end
        else
            set(appData.resultsTable, 'Data', []);
            set(appData.bestRatioText, 'String', {'No significant pairs found for any indicator.'}, 'Value', 1);
            set(appData.detailedResultsText, 'String', {'No significant pairs found with current thresholds.'}, 'Value', 1);
        end
    end


function saveAppDataCallback(~, ~)
%     appData = getappdata(fig, 'appData');
    % 直接从图形对象获取appData
    figHandle = findobj('Type', 'figure', 'Name', '3D-EEM Ratio Analyzer');
    if isempty(figHandle)
        return;
    end
    appData = getappdata(figHandle, 'appData');    
    if ~appData.dataLoaded && ~appData.calculationDone
        msgbox('No data to save! Please load data or perform calculation first.', 'Warning', 'warn');
        return;
    end
    
    try
        % 让用户选择保存位置
        [filename, pathname] = uiputfile('*.mat', 'Save App Data As');
        if filename == 0
            return; % 用户取消了保存
        end
        
        fullpath = fullfile(pathname, filename);
        
        % 创建要保存的数据结构，排除图形句柄等不适合保存的对象
        savedData = struct();
        
        % 保存数据相关字段
        dataFields = {
            'dataLoaded', 'calculationDone', ...
            'Results', 'IF_r', 'raw', ...
            'EEM_dataname', 'IF_dataname', ...
            'Ex', 'Em', 'nEx', 'nEm', ...
            'r', 'p', 'exm', 'PPP', 'Ind_output', ...
            'pv', 'rv', 'IND', ...
            'currentSelection', 'currentFitData', ...
            'regionSelection', 'regionData'
        };
        
        for i = 1:length(dataFields)
            if isfield(appData, dataFields{i})
                savedData.(dataFields{i}) = appData.(dataFields{i});
            end
        end
        
        % 添加保存时间和版本信息
        savedData.saveInfo = struct(...
            'saveTime', datestr(now, 'yyyy-mm-dd HH:MM:SS'), ...
            'version', 'EEM_Ratio_Analyzer_v1.0', ...
            'description', 'Saved application data from EEM Ratio Analyzer' ...
        );
        
        % 保存到文件
        save(fullpath, 'savedData','-v7.3');
        
        % 更新状态信息
        infoStr = get(appData.dataInfoText, 'String');
        infoStr{end+1} = '----------------------------------------';
        infoStr{end+1} = sprintf('App data saved successfully: %s', fullpath);
        infoStr{end+1} = sprintf('Save time: %s', savedData.saveInfo.saveTime);
        set(appData.dataInfoText, 'String', infoStr, 'Value', length(infoStr));
        
        msgbox(sprintf('Application data saved successfully to:\n%s', fullpath), 'Save Complete');
        
    catch ME
        msgbox(sprintf('Error saving app data: %s', ME.message), 'Save Error', 'error');
    end
end


function loadAppDataCallback(~, ~)
%     appData = getappdata(fig, 'appData');
    % 直接从图形对象获取appData
    figHandle = findobj('Type', 'figure', 'Name', '3D-EEM Ratio Analyzer');
    if isempty(figHandle)
        return;
    end
    appData = getappdata(figHandle, 'appData');    
    try
        % 让用户选择要加载的文件
        [filename, pathname] = uigetfile('*.mat', 'Select App Data File');
        if filename == 0
            return; % 用户取消了加载
        end
        
        fullpath = fullfile(pathname, filename);
        
        % 加载数据
        loadedFile = load(fullpath);
        if ~isfield(loadedFile, 'savedData')
            error('Invalid app data file format.');
        end
        
        savedData = loadedFile.savedData;
        
        % 验证文件格式
        if ~isfield(savedData, 'saveInfo') || ~isfield(savedData.saveInfo, 'version')
            error('Invalid app data file: missing version information.');
        end
        
        % 更新状态信息
        infoStr = get(appData.dataInfoText, 'String');
        infoStr{end+1} = '----------------------------------------';
        infoStr{end+1} = sprintf('Loading app data from: %s', fullpath);
        infoStr{end+1} = sprintf('Original save time: %s', savedData.saveInfo.saveTime);
        set(appData.dataInfoText, 'String', infoStr, 'Value', length(infoStr));
        drawnow;
        
        % 将加载的数据合并到当前appData中
        fields = fieldnames(savedData);
        for i = 1:length(fields)
            fieldName = fields{i};
            % 跳过saveInfo字段，我们单独处理
            if strcmp(fieldName, 'saveInfo')
                continue;
            end
            appData.(fieldName) = savedData.(fieldName);
        end
        
        % 更新UI状态
%         updateUIAfterDataLoad(appData);
        updateUIAfterDataLoad(appData, figHandle);
        setappdata(figHandle, 'appData', appData);
        
            
        % 更新状态信息
        infoStr = get(appData.dataInfoText, 'String');
        infoStr{end+1} = 'App data loaded successfully!';
        if appData.dataLoaded
            infoStr{end+1} = sprintf('Data status: Loaded (%d samples)', length(appData.EEM_dataname));
        end
        if appData.calculationDone
            infoStr{end+1} = sprintf('Calculation status: Completed (%d significant pairs)', size(appData.Ind_output, 1));
        end
        set(appData.dataInfoText, 'String', infoStr, 'Value', length(infoStr));
        
%         setappdata(fig, 'appData', appData);
        setappdata(figHandle, 'appData', appData);
        msgbox('Application data loaded successfully!', 'Load Complete');
        
    catch ME
        msgbox(sprintf('Error loading app data: %s', ME.message), 'Load Error', 'error');
        
        infoStr = get(appData.dataInfoText, 'String');
        infoStr{end+1} = sprintf('ERROR loading app data: %s', ME.message);
        set(appData.dataInfoText, 'String', infoStr, 'Value', length(infoStr));
    end
end

function updateUIAfterDataLoad(appData, figHandle)
    % 更新数据加载状态指示灯
    
    if appData.dataLoaded
        set(appData.dataStatusLamp, 'BackgroundColor', 'green');
    else
        set(appData.dataStatusLamp, 'BackgroundColor', [0.5, 0.5, 0.5]);
    end
    
    % 更新计算进度指示灯
    if appData.calculationDone
        set(appData.progressLamp, 'BackgroundColor', 'green');
        set(appData.progressText, 'String', 'Calculation completed (loaded from file)');
    else
        set(appData.progressLamp, 'BackgroundColor', [0.5, 0.5, 0.5]);
        set(appData.progressText, 'String', 'Ready for calculation');
    end
    
    % 更新指标下拉菜单
    if appData.dataLoaded && isfield(appData, 'raw') && size(appData.raw, 2) > 1
        indicatorNames = appData.raw(1,2:end);
        set(appData.visIndicatorPopup, 'String', indicatorNames);
        if isfield(appData, 'IND') && appData.IND <= length(indicatorNames)
            set(appData.visIndicatorPopup, 'Value', appData.IND);
        else
            set(appData.visIndicatorPopup, 'Value', 1);
        end
    end

    % 更新结果表格
    if appData.calculationDone && isfield(appData, 'Ind_output') && ~isempty(appData.Ind_output)
        updateResultsTable(appData);
        
    end
    
    % 更新计算信息
    if appData.calculationDone
        infoStr = get(appData.calcInfoText, 'String');
        if ~iscell(infoStr)
            infoStr = {infoStr};
        end
        infoStr{end+1} = '----------------------------------------';
        infoStr{end+1} = 'Calculation data loaded from saved file.';
        if isfield(appData, 'Ind_output')
            infoStr{end+1} = sprintf('Found %d significant wavelength pairs', size(appData.Ind_output, 1));
        else
            infoStr{end+1} = 'No significant pairs data found.';
        end
        set(appData.calcInfoText, 'String', infoStr, 'Value', length(infoStr));
    end
    
    % 刷新图形显示
    if appData.dataLoaded || appData.calculationDone
        try
            if isfield(appData, 'updatePlotBtn') && ~isempty(appData.updatePlotBtn)
                % 模拟点击更新绘图按钮
                updatePlotCallback([], []);
            end
        catch
            % 如果图形更新失败，忽略错误
        end
    end
end

% GPU加速的相关性计算函数
function [r, p] = corr5D2_gpu(X, IF, ind, nEm, nEx, type)
    batchSize = 15;
    r = zeros(1, nEm, nEx, nEm, nEx);
    p = zeros(1, nEm, nEx, nEm, nEx);
    
    for i = 1:batchSize:nEm
        range_i = i:min(i+batchSize-1, nEm);
        X_batch = X(:, range_i, :, :, :);
        X_batch(isinf(X_batch)) = NaN;
        
        IF_5d = repmat(IF(:,ind), [1, length(range_i), nEx, nEm, nEx]);
        IF_5d(isnan(X_batch)) = NaN;
        n = sum(~isnan(IF_5d), 1);
        
        switch type
            case 'Pearson'
                XX = X_batch;
                YY = IF_5d;
            case 'Spearman'
                XX = reshape(tiedrank(reshape(X_batch,...
                    [size(X_batch,1), length(range_i)*nEx*nEm*nEx])),...
                    [size(X_batch,1), length(range_i), nEx, nEm, nEx]);
                YY = reshape(tiedrank(reshape(IF_5d,...
                    [size(IF_5d,1), length(range_i)*nEx*nEm*nEx])),...
                    [size(IF_5d,1), length(range_i), nEx, nEm, nEx]);
        end
        
        % GPU计算
        XX = gpuArray(XX);
        YY = gpuArray(YY);
        
        numerator = sum((XX - repmat(mean(XX,1,'omitnan'), size(XX,1), 1)) .*...
            (YY - repmat(mean(YY,1,'omitnan'), size(YY,1), 1)),...
            1, 'omitnan');
        denominator = sqrt(sum((XX - repmat(mean(XX,1,'omitnan'), size(XX,1), 1)).^2,...
            1, 'omitnan') .* ...
            sum((YY - repmat(mean(YY,1,'omitnan'), size(YY,1), 1)).^2,...
            1, 'omitnan'));
        
        r0 = numerator ./ denominator;
        r0(n == 2) = NaN;
        r0(abs(r0) > 1) = NaN;
        
        t = r0 .* sqrt(n - 2) ./ sqrt(1 - r0.^2);
        t1 = gather(t);
        p0 = 2 * (1 - tcdf(abs(t1), n - 2));
        
        r(1, range_i, :, :, :) = gather(r0);
        p(1, range_i, :, :, :) = p0;
    end
end